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

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>

Related

fabric.js: How to set stroke thickness of selection box and controls?

In fabric.js, how do you adjust stroke thickness for the object selection box and control handles?
There's a bunch of customization options available, however it isn't clear on how you can customized stroke thickness. Is it possible, perhaps through an indirect way?
Note: The properties selectionColor, selectionBorderColor, selectionLineWidth are misleading... they have to do with the temporary selection box that appears when attempting to do a fresh drag-select across the canvas. Once your selection is made, it disappears and then you see the persistent object selection box with control handles (the thing I'm trying to customize).
See links:
http://fabricjs.com/customization
http://fabricjs.com/controls-customization
Ok here's a 2-part solution:
https://codepen.io/MarsAndBack/pen/bGExXzd
For the selection box stroke thickness:
Use fabric.Object.prototype.set to customize any object selection globally. Also, borderScaleFactor is documented, but not included in the fabric.js customization demos:
fabric.Object.prototype.set({
borderScaleFactor: 6
})
For the control handle stroke thickness:
Here we override differently, and actually draw new elements using standard HTML5 canvas properties. Through this method you could also target specific control handles and even use image icons.
fabric.Object.prototype._drawControl = controlHandles
fabric.Object.prototype.cornerSize = 20
function controlHandles (control, ctx, methodName, left, top) {
if (!this.isControlVisible(control)) {
return
}
var size = this.cornerSize
// Note 1: These are standard HTML5 canvas properties, not fabric.js.
// Note 2: Order matters, for instance putting stroke() before strokeStyle may result in undesired effects.
ctx.beginPath()
ctx.arc(left + size / 2, top + size / 2, size / 2, 0, 2 * Math.PI, false);
ctx.fillStyle = "pink"
ctx.fill()
ctx.lineWidth = 4 // This is the stroke thickness
ctx.strokeStyle = "red"
ctx.stroke()
}
SO code snippet:
const canvas = new fabric.Canvas("myCanvas")
canvas.backgroundColor="#222222"
this.box = new fabric.Rect ({
width: 240,
height: 100,
fill: '#fff28a',
myType: "box"
})
canvas.add(this.box)
this.box.center()
// Selection box border properties
// ----------------------------------------
fabric.Object.prototype.set({
borderColor: "white",
borderScaleFactor: 6
})
// Control handle properties
// ----------------------------------------
fabric.Object.prototype._drawControl = controlHandles
fabric.Object.prototype.cornerSize = 20
function controlHandles (control, ctx, methodName, left, top) {
if (!this.isControlVisible(control)) {
return
}
var size = this.cornerSize
// Note 1: These are standard HTML5 canvas properties, not fabric.js.
// Note 2: Order matters, for instance putting stroke() before strokeStyle may result in undesired effects.
ctx.beginPath()
ctx.arc(left + size/2, top + size/2, size/2, 0, 2 * Math.PI, false);
ctx.fillStyle = "pink"
ctx.fill()
ctx.lineWidth = 4
ctx.strokeStyle = "red"
ctx.stroke()
}
<script src="https://pagecdn.io/lib/fabric/3.6.3/fabric.min.js"></script>
<canvas id="myCanvas" width="700" height="400"></canvas>

fabricjs diagonal lines hovercursor and selectable

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.

OpenLayers 3 Stroke style

I want to modify style of the method select . I'm able to change the style of this method but i'm not able to duplicate the white border of blue stroke.
Someone is able to style vector with a stroke and put a border to the stroke?
See this example, for understand what i'm talking about:
http://openlayers.org/en/v3.4.0/examples/select-features.html
The trick is that you have two styles. With the first style you are drawing a white line, with the second style a thinner blue line on top:
var width = 3;
var styles = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'white',
width: width + 2
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'blue',
width: width
})
})
];

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