setAngle is not a function fabricjs - javascript

I recently started to work with fabricjs, and I have a question about connectivity object. i do creating sample demo for connectivity from parent object to child object connect with arrow. I got sample demo http://kpomservices.com/HTML5CanvasCampaign/campaign.html. This code should work with fabric 1.4.2.A similar code is possible for the version 2.3.3 not work.
Error functions.js:963 Uncaught TypeError: c.setAngle is not a function
code
function makeArrow(centerpt, left, top, line) {
var c = new fabric.Triangle({
width: 10,
height: 10,
left: left,
top: top,
//selectable: false,
strokeWidth: 3,
fill: 'grey',
opacity: 1,
stroke: 'grey',
originX: 'center',
originY: 'center'
});
c.hasBorders = c.hasControls = false;
c.angle = 90;
c.line = line;
var dx = left - centerpt.x;
var dy = top - centerpt.y;
var angle = Math.atan2(dy, dx) * 180 / Math.PI;
c.setAngle(angle + 90);
c.setCoords();
c.name = 'ep';
line.ep = c;
c.line = line;
return c;
}

Build doesn't have setter/getter (optional). You can make your build here with Named accessors. If you want to set angle you can use
obj.angle = text;
//or
obj.set({
angle:angle
});
//or
obj.set('angle', angle);
DEMO
var canvas = new fabric.Canvas('c');
var triangle = new fabric.Triangle({
left: 150,
top: 50,
width: 300,
height:200,
fill:'',
stroke:'red'
})
canvas.add(triangle);
triangle.set('angle',40);
//triangle.angle = 40;
//triangle.set({angle : 40})
canvas{
border:1px solid #000;
}
<script type="text/javascript" src="
https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>

Related

Offset issues images when inside group (scaleToWidth)

I'm experiencing an issue when scaling an image inside a group the offset of the image changes. The group consists of a background (Rect) and an image. When scaling the group the offset if the image becomes different. Expected is that the offset remains the same as the background.
I'm using Fabric 4.0.0-beta.6
const canvas = new fabric.Canvas('canvas');
canvas.setWidth(document.body.clientWidth);
canvas.setHeight(document.body.clientHeight);
const bg = new fabric.Rect({
width: 100,
height: 100,
fill: 'red',
});
fabric.Image.fromURL("https://dummyimage.com/300x150/000/fff", function(img) {
img.scaleToWidth(bg.width)
const post = new fabric.Group([bg, img], {
left: 100,
top: 100,
});
post.scaleToWidth(400);
canvas.add(post);
canvas.renderAll();
});
https://jsbin.com/migogekoxu/1/edit?html,css,js,output
Setting the strokeWidth property of the background element to 0 fixed the offset for me.
const canvas = new fabric.Canvas('canvas');
canvas.setWidth(document.body.clientWidth);
canvas.setHeight(document.body.clientHeight);
const bg = new fabric.Rect({
width: 100,
height: 100,
fill: 'red',
strokeWidth: 0, //<---
});
fabric.Image.fromURL("https://dummyimage.com/300x150/000/fff", function(img) {
img.scaleToWidth(bg.width)
const post = new fabric.Group([bg, img], {
left: 100,
top: 100,
});
post.scaleToWidth(400);
canvas.add(post);
canvas.renderAll();
});
<canvas id="canvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/fabric#4.0.0-beta.6-browser/dist/fabric.min.js"></script>
Obviously that's a bug with fabricJS. If you don't want to fix it on your own in it's source code you can workaround it however.
You can manually correct the position by adding an offset of 0.5 to the image's top and left properties.
For example:
const canvas = new fabric.Canvas('canvas');
const bg = new fabric.Rect({
width: 100,
height: 100,
fill: 'red'
});
fabric.Image.fromURL("https://dummyimage.com/300x150/000/fff", function(img) {
img.scaleToWidth(bg.width);
img.left += 0.5;
img.top += 0.5;
const post = new fabric.Group([bg, img], {
left: 100,
top: 100
});
post.scaleToWidth(400);
canvas.add(post);
canvas.renderAll();
});
<script src="https://cdn.jsdelivr.net/npm/fabric#4.0.0-beta.6-browser/dist/fabric.min.js"></script>
<canvas id="canvas" width="600" height="400"></canvas>

Fabric.js : changing originX in ellipse changes left position

I am having a situation where I am drawing a ellipse in fabric.js from originX='right' and
afterwards changing it to originX='left'.
What I see is after changing the originX to left and adjusting the left by the following calculation :
ellipse.left -= ellipse.width
I still see a difference in the left positions.
To explain it , I added a fiddle where I added a timeout of 3 seconds before changing the originX. So, please open the fiddle and wait 3 seconds and see how the position changes which ideally shouldn't .
Any mistakes I am doing or any suggestions ?
Code :
var canvas = new fabric.Canvas('paper');
var ellipse = new fabric.Ellipse({
left: 300,
top: 10,
rx: 145,
ry: 65,
strokeWidth: 4,
stroke: 'blue',
fill: '',
originX: 'right',
originY: 'top'
});
canvas.add(ellipse);
canvas.renderAll();
var log = document.getElementById('log');
log.innerHTML = ellipse.left;
//changing the origin
setTimeout(function() {
ellipse.originX = 'left';
ellipse.left -= ellipse.width;
canvas.renderAll();
log.innerHTML += ', ' + ellipse.left;
}, 3000);
Since, the ellipse­'s stroke has some width to it, hence, you would also need to exclude that, from ellipse­'s left position, like so ...
ellipse.left -= ellipse.width + ellipse.strokeWidth;
or
ellipse.left = ellipse.left - ellipse.width - ellipse.strokeWidth;
Here is the revised version of your code ...
var canvas = new fabric.Canvas('paper', {
isDrawingMode: false
});
var ellipse = new fabric.Ellipse({
left: 300,
top: 10,
rx: 145,
ry: 65,
strokeWidth: 4,
stroke: 'blue',
fill: false,
originX: 'right',
originY: 'top'
});
canvas.add(ellipse);
canvas.renderAll();
var log = document.getElementById('log');
log.innerHTML = ellipse.left;
//changing the origin
setTimeout(function() {
ellipse.originX = 'left';
ellipse.left -= ellipse.width + ellipse.strokeWidth;
canvas.renderAll();
log.innerHTML += ', ' + ellipse.left;
}, 3000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.11/fabric.min.js"></script>
<canvas id="paper" width="400" height="400" style="border:1px solid #ccc"></canvas>
<div id='log'></div>

Fabricjs - Get objects in group to be based on left wall

My fiddle: http://jsfiddle.net/yeftc60v/1/
So I'm trying to get the obj.left to be based on the left side(wall) of the group instead of the center. So right now, when I try to get the left of an object, if it's on the left side, it will return a negative number.
I've tried both setOriginY and setOriginX but they don't have any effect.
I'm working around this by doing some maths based on the group's width.
Right now if you hit the "clone" button, the left values read negative values (-100.5 and -0.5). Instead they should be 0 and 99.5(I think), respectively.
Unfortunately, any active group­'s origin x and y will always be at center. This won't take originX and originY property into consideration, hence setting setOriginX and setOriginY won't have any effect.
To get around this, you need to manually calculate the object­'s top and left position respective to the selected group, like so ...
let objLeft = obj.left + (active.width / 2);
let objTop = obj.top + (active.height / 2);
ᴅᴇᴍᴏ
var canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
left: 50,
top: 50,
fill: "#FF0000",
stroke: "#000",
width: 100,
height: 100,
strokeWidth: 1,
opacity: .8
});
var rect1 = new fabric.Rect({
left: 150,
top: 150,
fill: "#FF0000",
stroke: "#000",
width: 100,
height: 100,
strokeWidth: 1,
opacity: .8
});
canvas.add(rect);
canvas.add(rect1);
function clone() {
let active = canvas.getActiveGroup();
if (active) {
active.forEachObject(obj => {
let clone = obj.clone();
// get object's left & top relative to the group
let objLeft = obj.left + (active.width / 2);
let objTop = obj.top + (active.height / 2);
clone.setLeft(objLeft + active.left);
clone.setTop(objTop + active.top);
canvas.add(clone);
});
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.11/fabric.min.js"></script>
<canvas id="c" width="300" height="300" style="border: 1px solid black;"></canvas>
<button onclick="clone()">
Clone
</button>

Fabric.js - Attach object creation to mouse click

When you create a new fabric object, you can specify the location for it to appear on the canvas. Is there a way to attach the generated object to the mouse and then place the object on click (or touch)?
E.g. way to generate a circle which appears on the canvas.
var circle = new fabric.Circle({
radius: 20, fill: 'green', left: 100, top: 100
});
It's fairly easy to update the position of an object to match that of the mouse's position and on mouse:up clone that object and place it on the canvas.
var canvas = new fabric.Canvas('c');
var mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: 5,
fill: '#9f9',
originX: 'right',
originY: 'bottom',
})
canvas.add(mousecursor);
canvas.on('mouse:move', function(obj) {
mousecursor.top = obj.e.y - mousecursor.radius;
mousecursor.left = obj.e.x - mousecursor.radius;
canvas.renderAll()
})
canvas.on('mouse:out', function(obj) {
// put circle off screen
mousecursor.top = -100;
mousecursor.left = -100;
canvas.renderAll()
})
canvas.on('mouse:up', function(obj) {
canvas.add(mousecursor.clone())
canvas.renderAll()
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
var canvas = new fabric.Canvas('c');
var mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: 50,
fill: '#9f9',
originX: 'right',
originY: 'bottom',
})
canvas.add(mousecursor);
canvas.on('mouse:move', function(obj) {
mousecursor.top = obj.e.y;
mousecursor.left = obj.e.x;
canvas.renderAll()
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

JavaScript - Dynamically create SVG and modify for cursor

Say I have a HTML5 canvas (In this case using fabric.js), and I want to change the cursor over the canvas to represent whatever brush size and colour has been selected. I'm thinking there should be a way to do this by changing an SVG's properties (size & colour) dynamically with JS so we don't have to use multiple images. Any ideas on if this is possible?
var canvas = new fabric.Canvas(c, {
isDrawingMode: true,
freeDrawingCursor: 'url("img/cursor.svg"), auto'
});
I think freeDrawingCursor is just looking for normal css property names. Here is an example of how to have a fabric object represent the cursor size and color:
var canvas = new fabric.Canvas('c', {
isDrawingMode: true,
freeDrawingCursor: 'none'
});
canvas.freeDrawingBrush.width = 10;
canvas.freeDrawingBrush.color = '#9f9';
var mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: canvas.freeDrawingBrush.width / 2,
fill: canvas.freeDrawingBrush.color,
originX: 'right',
originY: 'bottom',
})
canvas.add(mousecursor);
canvas.on('mouse:move', function(obj) {
mousecursor.top = obj.e.y - mousecursor.radius;
mousecursor.left = obj.e.x - mousecursor.radius;
canvas.renderAll()
})
canvas.on('mouse:out', function(obj) {
// put circle off screen
mousecursor.top = -100;
mousecursor.left = -100;
canvas.renderAll()
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
Existing answers didn't work for me in 2020. Try the following:
this.canvas.isDrawingMode = true;
this.canvas.freeDrawingCursor = 'none';
const mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: this.canvas.freeDrawingBrush.width / 2,
fill: this.canvas.freeDrawingBrush.color,
originX: 'right',
originY: 'bottom',
});
this.canvas.add(mousecursor);
// Cursor in canvas
this.canvas.on('mouse:move', event => {
mousecursor.top = event.e.layerY + mousecursor.radius;
mousecursor.left = event.e.layerX + mousecursor.radius;
this.canvas.renderAll();
});
// Cursor out of canvas
this.canvas.on('mouse:out', event => {
mousecursor.top = -100;
mousecursor.left = -100;
this.canvas.renderAll();
});
Worked fine with Angular 7.
I was looking for the same and found my way to this question. Unfortunately the solution by STHayden is not working for me. So I've modified it a bit and came up with the code below. It uses two canvas layers, the bottom for drawing, the top for the "cursor". Works pretty well for me now, maybe someone will find it helpful :)
//drawing layer
var canvas = new fabric.Canvas("draw", {
isDrawingMode: true,
freeDrawingCursor: 'none'
});
//mouse cursor layer
var cursor = new fabric.StaticCanvas("cursor");
canvas.freeDrawingBrush.width = 20;
canvas.freeDrawingBrush.color = '#ff0000';
var cursorOpacity = .5;
//create cursor and place it off screen
var mousecursor = new fabric.Circle({
left: -100,
top: -100,
radius: canvas.freeDrawingBrush.width / 2,
fill: "rgba(255,0,0," + cursorOpacity + ")",
stroke: "black",
originX: 'center',
originY: 'center'
});
cursor.add(mousecursor);
//redraw cursor on new mouse position when moved
canvas.on('mouse:move', function (evt) {
var mouse = this.getPointer(evt.e);
mousecursor
.set({
top: mouse.y,
left: mouse.x
})
.setCoords()
.canvas.renderAll();
});
//put cursor off screen again when mouse is leaving
canvas.on('mouse:out', function () {
mousecursor
.set({
top: mousecursor.originalState.top,
left: mousecursor.originalState.left
})
.setCoords()
.canvas.renderAll();
});
//while brush size is changed show cursor in center of canvas
document.getElementById("size").oninput = function () {
var size = parseInt(this.value, 10);
mousecursor
.center()
.set({
radius: size/2
})
.setCoords()
.canvas.renderAll();
};
//after brush size has been changed move offscreen, update brush size
document.getElementById("size").onchange = function () {
var size = parseInt(this.value, 10);
canvas.freeDrawingBrush.width = size;
mousecursor
.set({
left: mousecursor.originalState.left,
top: mousecursor.originalState.top,
radius: size/2
})
.setCoords()
.canvas.renderAll();
};
//change mousecursor opacity
document.getElementById("opacity").onchange = function () {
cursorOpacity = this.value;
var fill = mousecursor.fill.split(",");
fill[fill.length-1] = cursorOpacity + ")";
mousecursor.fill = fill.join(",");
};
//change drawing color
document.getElementById("color").onchange = function () {
canvas.freeDrawingBrush.color = this.value;
var bigint = parseInt(this.value.replace("#", ""), 16);
var r = (bigint >> 16) & 255;
var g = (bigint >> 8) & 255;
var b = bigint & 255;
mousecursor.fill = "rgba(" + [r,g,b,cursorOpacity].join(",") + ")";
};
#cont {
position: relative;
width: 500px;
height: 500px;
}
canvas {
border: 1px solid;
}
#cont canvas, .canvas-container {
position: absolute!important;
left: 0!important;
top: 0!important;
width: 100%!important;
height: 100%!important;
}
#cursor {
pointer-events: none!important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
Color: <input id="color" type="color" value="#ff0000"><br/>
Brush size: <input id="size" type="range" min="1" max="100" step="1" value="20"><br/>
Brush opacity: <input id="opacity" type="number" min="0" max="1" step="0.1" value="0.5"><br/>
<div id="cont">
<canvas id="draw" width="500" height="500"></canvas>
<canvas id="cursor" width="500" height="500"></canvas>
</div>

Categories

Resources