fabricjs diagonal lines hovercursor and selectable - fabricjs

I have lines in fabricjs which may be at an angle. I want the user to be able to select them, but the selection outline is a rectangle with corners at the ends of the line. The user should only be able to select the line when the cursor is over the line, or at least within a few pixels of it. So I use the mousemove event to set the cursor when it's over the line and will do other things when he clicks on it.
But fabricjs only lets me set the cursor when selectable is true and then the user gets this blue rectangle around the line, which is not helpful. How can I get rid of this rectangle, or have the cursor change when selectable is false?

First, add perPixelTargetFind and targetFindTolerance to fabric.Canvas instance.
var canvas = new fabric.Canvas('canvas', {
perPixelTargetFind: true,
targetFindTolerance: 5
});
Then, add padding to fabric.Line instance.
var line = new fabric.Line([50, 50, 250, 250], {
padding: 5
});
canvas.add(line);
The targetFindTolerance numeric value is only respected by diagonal lines as far as I can tell. The padding numeric value is only respected by horizontal lines as far as I can tell. Both targetFindTolerance and padding must be set for either type of line to respect the rule. It's unclear whether this is buggy or intentional behavior.

This should get you fairly close, if I understood you correctly:
Here's the JavaScript code:
var canvas = new fabric.Canvas('canvas', {
width: 300,
height: 300,
perPixelTargetFind: true,
selection: false,
hoverCursor: 'default'
});
line = new fabric.Line([50, 50, 250, 250], {
strokeWidth: 5,
stroke: 'black',
originX: 'center',
originY: 'center',
hasControls: false,
hasBorders: false,
targetFindTolerance: 8
});
canvas.add(line);
And finally the all important JSFiddle, https://jsfiddle.net/rekrah/tvcufesq/.
Let me know if you have any more questions. Always happy to help!

try add padding and targetFindTolerance to line.

Related

Fabric.js: parts of Line not rendered after updating its dimensions programmatically

I draw a line, then try to change it, leaving the same starting point with x1(left) and x1(top) and moving the endpoint by changing the line's width (x2-x1 - negative when moved left of originating point) and height (determined by y2-y1).
The line is drawn repeatedly with positive width value but 90% of the time it has gaps in the stroke as if the line is not fully stretched from border to border.
Below I define the line, it works well and connects my 2 points. Then, I modify the line when one of the flow objects is moved. When I move the bottom object to the right (positive width), it works fine, when I move to the left (negative width) the line does not reach its borders. The line has borders: true so I can see that the borders are lined up perfectly with the flow objects they are trying to connect (visible in the images).
//[startleft, starttop, endleft, endtop]
canvas.add(new fabric.Line(
[globalConnect[0], globalConnect[1], globalConnect[2], globalConnect[3]], {
stroke:'black',
strokeWidth:3,
lockScalingX:true,
lockScalingY:true,
lockRotation:true,
hasControls:true,
hasBorders:true,
lockMovementX:true,
lockMovementY:true
})
);
canvas.item(tempObjectIdx + 1).left = tempX1;
canvas.item(tempObjectIdx + 1).top = tempY1;
canvas.item(tempObjectIdx + 1).width = tempX2-tempX1;
canvas.item(tempObjectIdx + 1).height = tempY2-tempY1;
Example of the line when it's not fully drawn: screenshot
Example of what line looks like with positive width or negative width when it works fine: screenshot
Anybody having similar problems with negative widths when redrawing a line? Is there something to do with origination point - or recalculating coordinates, I do redraw canvas after setting these values - works great for positive value, but the line does not span the border box when width is negative (I have tried redrawing line from bottom origin with positive width and negative height - no better?)
If you just need the line to connect two points and update it whenever those two points are updated, you only have to set the line's x1,y1 and x2,y2 on each appropriate event. Here's an example where such line is updated when the boxes fire moving events:
const canvas = new fabric.Canvas('c')
const box1 = new fabric.Rect({
left: 50,
top: 50,
width: 100,
height: 100,
fill: 'green'
})
const box2 = new fabric.Rect({
left: 250,
top: 250,
width: 100,
height: 100,
fill: 'red'
})
const box1point = box1.getPointByOrigin('center', 'bottom')
const box2point = box2.getPointByOrigin('center', 'top')
const connector = new fabric.Line(
[box1point.x, box1point.y, box2point.x, box2point.y],
{
stroke: "black",
strokeWidth: 3,
lockScalingX: true,
lockScalingY: true,
lockRotation: true,
hasControls: true,
hasBorders: true,
lockMovementX: true,
lockMovementY: true
}
)
box1.on('moving', function() {
const connectPoint = this.getPointByOrigin('center', 'bottom')
connector.set({
x1: connectPoint.x,
y1: connectPoint.y
})
})
box2.on('moving', function() {
const connectPoint = this.getPointByOrigin('center', 'top')
connector.set({
x2: connectPoint.x,
y2: connectPoint.y
})
})
canvas.add(box1, box2, connector)
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<canvas id='c' width="500" height="400"></canvas>

(fabric.js) Can I change a position of a character in iText for vertical writing?

I am Japanese, and I want to write Japanese words vertically in Fabric.js.
Japanese language has small letters, and the positions of the them are top-left corner in vertical writing.
So, I want to change the position of a small letter in iText.
I thought that I can change the position of a character by using "styles" parameter of iText, so I wrote as follows.
var iTextSample = new fabric.IText('h\ne\nl\nl\no', {
left: 50,
top: 50,
fontFamily: 'Helvetica',
fill: '#333',
lineHeight: 1.1,
styles: {
1: {
0: { textDecoration: 'underline', ←★ WORK
fontSize: 80, ←★ WORK
top:-10,  ←★ NOT WORK
transformMatrix: [ 1, 0, 0, 1, 18, -50 ] ←★ NOT WORK
},
},
}
});
https://jsfiddle.net/uemon/tLy9eqj6/77/
The 'textDecoration' and 'fontSize' worked, but the 'top' or 'transformMatrix' didn't work.
Can't I use 'top' or 'transformMatrix' in the "styles" parameter ?
How can I change the position of one character ?
Thank you in advance.
So from the use of textDecoration property i guess you are on the 1.7 or similar version.
You should really move to the 2.0 version that has integrated support for multibyte languages and composition.
Said that, there is no support for vertical text in fabricjs at all.
This may change in the future.
You should really go here:
https://github.com/kangax/fabric.js/issues/511
refresh the request and maybe add some detail about it, because the actual mantainer may have no clue on how vertical text should work regarding input, decorations, multiple columns and so on.

Fabricjs : item locked but group selection possible

Basically I'm trying to reproduce this behavior for locking/unlocking item in fabricjs:
https://www.dropbox.com/s/undtb1v4kxqcbi8/ScreenFlow-lock.mp4?dl=0
=> I want to be able to lock an item, but still be able to clic and drag a selection from it, but still being able to select it (but not moving/scaling,etc).
I can lock an item and be able to start a drag selection from it:
https://jsfiddle.net/og09g5ex/
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 150,
height: 150,
transparentCorners: false,
evented:false,
selectable:false});
But then I can't select it because I use "evented=false".
Does anyone has an idea?
Many thanks!
This is possible but it is not easy. There is a findTarget in the canvas.class.js file that you will need to modify so that when you are clicking on the object you select it but when you are clicking then dragging it does not select it. naively fabric does not have this concept and modifying this function is the only way to get it. Hope that helps!

Fabric.js hasControls=false and hasBorders=false but it is still selectable

I was trying to add to canvas item which will be dragable but not selectable so I did like this
var canvas = new fabric.Canvas('root');
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
canvas.add(new fabric.Circle({ radius: 30, fill: '#5f5', top: 160, left: 100 }));
canvas.item(0).hasControls = canvas.item(0).hasBorders = false;
Now I'm not able to select as a group element 0 (this is ok!) but when I'm selecting group which contains also item 1 then item 0 is also selected (this is not good). How can I fix it?
I know this question is very old but:
canvas.item(0).hasControls = canvas.item(0).hasBorders = false;
Will make the object with invisible border and invisible controls, so it looks like you are not selecting it, but you are still doing and not drawing any controls.
There is no way to make an object unselectable BUT draggable.
If you cannot select it ( setting .selectable=false), you cannot drag it.
When an object is in a selection group its border get drawn anyway, whatever setting is on .hasBorders.

Make text grow uni-directionally on calling set('text', 'some value')

Currently, whenever I set the text of a fabric.Text object dynamically, using the set('text', 'some random text') function, the width seems to grow bi-directionally i.e from both the left and right side.
Is there any way to make it grow from either the left or right side only.
I have achieved this by explicitly calculating the top_left_x, top_left_y, top_right_x, top_right_y and using some arithmetic logic for the same.
But what is there any internal fabricJS property (or something similar) by which this can be achieved.
For ex: In the Kitchensink demo, if you add a new Text object and modify the text in the lower-right text area, you will see that the text grows from the right while its left side remains fixed. This is exactly what I wish to achieve.
Any suggestions anyone?
This happened because the default origin point is the center of object. So you need set the "originX" to "left". As you can see in the Kintchensink source file:
document.getElementById('add-text').onclick = function() {
var textSample = new fabric.Text(text.slice(0, getRandomInt(0, text.length)), {
left: getRandomInt(350, 400),
top: getRandomInt(350, 400),
fontFamily: 'helvetica',
angle: getRandomInt(-10, 10),
fill: '#' + getRandomColor(),
scaleX: 0.5,
scaleY: 0.5,
fontWeight: '',
originX: 'left',
hasRotatingPoint: true
});
canvas.add(textSample);
updateComplexity();
};

Resources