How to mapping "letter-spacing" value from text node of SVG to "charSpacing" property of fabric.TextBox in FabricJS? - html5-canvas

I have problem with how to re-presentation of node in SVG with "letter-spacing" in SVG document to fabric.TextBox.
In file SVG text node is:
<text transform="matrix(1 0 0 1 51.5211 22.2889)" style="fill:#3C2415; font-size:11px; letter-spacing:3;">MINH TUẤN</text>
And my fabric.TextBox is:
var textbox_0_1 = new fabric.Textbox("MINH TUẤN", {
width: 200,
fontSize: 11,
fill: "#3C2415",
editable: true,
textAlign: "center",
charSpacing: 3,
});
Here is display on SVG & FabricJS:
How to find correct charSpacing which is respectively with letter-spacing attribute in SVG's Text node ?
Notes:
In fabric.TextBox document write:
charSpacing :Number
additional space between characters expressed in thousands of em unit
And in document for SVG write:
(if no unit identifier is provided) values in user space — for example, "15"
And Here is my code:
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
var textbox_0_1 = new fabric.Textbox("MINH TUẤN", {
top: 20,
left: 20,
width: 200,
fontSize: 11,
fill: "#000000",
editable: true,
textAlign: "center",
charSpacing: 3,
});
canvas.add(textbox_0_1);
setObjectCoords();
canvas.renderAll();
function setObjectCoords() {
canvas.forEachObject(function(object) {
object.setCoords();
});
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
Thank you,

You need to parse from pixel to em.
DEMO
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
width: 300,
height: 100
});
var letterSpacing = 5, fontSize = 30;
var textbox = new fabric.Text("MINH TUẤN", {
top: 20,
fontSize: fontSize,
fill: "#000000",
fontFamily : "Verdana"
});
canvas.add(textbox);
var parsedSpacing = fabric.util.parseUnit(letterSpacing, fontSize) / fontSize * 1000;
textbox.set({charSpacing : parsedSpacing});
canvas.requestRenderAll();
console.log(parsedSpacing)
canvas{
border:1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<svg width="300" height="100" viewBox="0 0 300 100">
<text font-size="30" letter-spacing="5" font-family="Verdana" y="40">MINH TUẤN</text>
</svg>
<canvas id="editorCanvas"></canvas>

Related

How to increase touch area control points on mobile device ( not increase display size of control points ) in fabricjs?

How to increase touch area of control points on mobile device with FabricJS? Because on mobile they are too small for smooth interactive with. But not change size of control points ( for nice view ).
Here is my code:
How to increase interactive of control points = view control points size x 2 ?
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
// test customize control points
var rect = new fabric.Rect({
left: 30,
top: 30,
fill: 'red',
width: 150,
height: 150
});
canvas.add(rect);
rect.set({
transparentCorners: false,
cornerColor: 'white',
cornerStrokeColor: 'rgba(14,19,24,.15)',
borderColor: 'rgba(41,198,203,1)',
selectionLineWidth: 8,
cornerSize: 12,
cornerStyle: 'circle',
});
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
Please show me the way to resolve this problem.
By the way: ( on mobile device ) is there any way to allow drag object only object is selected before?
Thank you very much!
You need to override _setCornerCoords method of object and change the value of cornerHypotenuse.
DEMO
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
// test customize control points
var rect = new fabric.Rect({
left: 30,
top: 30,
fill: 'red',
width: 150,
height: 150
});
canvas.add(rect);
rect.set({
transparentCorners: false,
cornerColor: 'white',
cornerStrokeColor: 'rgba(14,19,24,.15)',
borderColor: 'rgba(41,198,203,1)',
selectionLineWidth: 8,
cornerSize: 5,
cornerStyle: 'circle'
});
rect._setCornerCoords = function() {
var coords = this.oCoords,
newTheta = fabric.util.degreesToRadians(45 - this.angle),
cornerHypotenuse = this.cornerSize * 2 * 0.707106,
cosHalfOffset = cornerHypotenuse * fabric.util.cos(newTheta),
sinHalfOffset = cornerHypotenuse * fabric.util.sin(newTheta),
x, y;
for (var point in coords) {
x = coords[point].x;
y = coords[point].y;
coords[point].corner = {
tl: {
x: x - sinHalfOffset,
y: y - cosHalfOffset
},
tr: {
x: x + cosHalfOffset,
y: y - sinHalfOffset
},
bl: {
x: x - cosHalfOffset,
y: y + sinHalfOffset
},
br: {
x: x + sinHalfOffset,
y: y + cosHalfOffset
}
};
}
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>

How to create an Editable Text which is curved along a Path in Fabricjs?

I want to make Editable Text which is curved along a fabric.Path as bellow expected image.
Here is my code:
I created a curved fabric.Path & a fabric.TextBox, but I don't know how to curve text along that Path. Please help me resolve this problem.
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
var Path_0_1 = new fabric.Path('M127.91,99.29c32.16,10.73,53.41,7.33,67.81,0 c34.07-17.34,41.99-62.82,60.98-60.98c8.19,0.79,14.11,9.98,17.91,17.91', {
fill : null,
stroke: '#000000',
});
canvas.add(Path_0_1);
var curvedText = new fabric.IText("Anh Minh", {
left: 50,
top: 50,
width: 200,
fontSize: 24,
fontFamily: 'Times New Roman',
fontWeight: 'normal',
textAlign: 'center',
lineHeight: 1,
fill: "#404041",
});
canvas.add(curvedText);
#canvasContainer {
width: 100%;
height: 500px;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
Addition information:
After few hours google search, I see an interesting Konva.TextPath, I wonder If can we make same Object like that Konva.TextPath in Fabric.js?
Thank you!

Why fabric.Path on FabricJS is display different from svg file?

I want to display an path in Fabric.JS, in svg file:
<g>
<path style="fill:none;stroke:#000000;stroke-miterlimit:10;"
d="M221.58-0.55 c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72"/>
</g>
And code in my Fabricjs
var Path_0_1 = new fabric.Path('M221.58-0.55 c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72', {
fill: 'none',
stroke: '#000000',
strokeMiterLimit: 10,
opacity: 1,
});
But result is not same:
Expected:
Path in FabricJS display same as in SVG file.
Here is my code:
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
var Path_0_1 = new fabric.Path('M221.58-0.55 c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72', {
// fill : 'none',
stroke: '#000000',
strokeMiterLimit: 10,
opacity: 1,
});
canvas.add(Path_0_1);
canvas.moveTo(Path_0_1, 1);
setObjectCoords();
canvas.renderAll();
function setObjectCoords() {
canvas.forEachObject(function(object) {
object.setCoords();
});
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
And here is my svg file:
https://svgur.com/s/Bw6
Set fill value '' || null || 'transparent', so on ctx.fill() it wont fill anything to the object.
DEMO
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
var Path_0_1 = new fabric.Path('M221.58-0.55c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72', {
fill : null,
stroke: '#000000',
});
canvas.add(Path_0_1);
#canvasContainer {
width: 100%;
height: 100vh;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>

How to set absolute position for each item in IText Fabricjs

Please help me, how to set absolute position of each text item in IText Fabricjs. In this example, I want text "KÍNH MỜI" is align horizontal center with below text.
Expected Result:
Actual Result:
Here is my code:
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
var textbox1 = new fabric.IText("KÍNH MỜI\n \n.......................................................................................", {
left: 162,
top: 50,
width: 216.125889,
fontSize: 11.3735,
fontFamily: 'Times New Roman',
fontWeight: 'normal',
fill: "#404041",
editable: false,
styles: {
0: {
0: { fontFamily: 'Times New Roman', fontSize: '11.3735', fill: '#404041' }
},
1: {
0: { fontFamily: 'Times New Roman', fontSize: '11.3735', fill: '#404041' }
},
2: {
0: { fontFamily: 'Times New Roman', fontSize: '7.4898', fill: '#404041' }
}
}
});
canvas.add(textbox1);
canvas.renderAll();
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
You need textAlign: center. I also changed lineHeight to 1 (default is 1.16) to make it look more like your expected result.
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
var textbox1 = new fabric.IText("KÍNH MỜI\n \n.......................................................................................", {
left: 162,
top: 50,
width: 216.125889,
fontSize: 11.3735,
fontFamily: 'Times New Roman',
fontWeight: 'normal',
textAlign: 'center',
lineHeight: 1,
fill: "#404041",
editable: false,
styles: {
0: {
0: { fontFamily: 'Times New Roman', fontSize: '11.3735', fill: '#404041' }
},
1: {
0: { fontFamily: 'Times New Roman', fontSize: '11.3735', fill: '#404041' }
},
2: {
0: { fontFamily: 'Times New Roman', fontSize: '7.4898', fill: '#404041' }
}
}
});
canvas.add(textbox1);
canvas.renderAll();
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>

Fabric toDataUrl with multiplier not working as expected

In my code I created method to clip images using fabric shapes. I have used stackoverflow answer for achieving this. Somehow after using this method I cannot render the canvas using default fabric canvas render method.
var img01URL = 'https://www.google.com/images/srpr/logo4w.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var canvas = new fabric.Canvas('c');
document.getElementById('download').addEventListener('click', function() {
canvas.renderAll();
this.href = canvas.toDataURL({
format: 'png',
multiplier: 2
});
this.download = "test.png";
}, false);
var clipRect1 = new fabric.Rect({
originX: 'left',
originY: 'top',
angle: 90,
left: 195,
top: 0,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
angle: 5,
stroke: 'red'
});
var pugImg = new Image();
pugImg.onload = function (img) {
var pug = new fabric.Image(pugImg, {
angle: 0,
width: 500,
height: 500,
left: 245,
top: 35,
scaleX: 0.3,
scaleY: 0.3,
clipName: 'pug',
clipTo: function(ctx) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clipRect1.render(ctx);
ctx.restore();
}
});
canvas.add(pug);
};
pugImg.src = img02URL;
pugImg.setAttribute('crossOrigin', 'anonymous');
#c {
border:0px solid #ccc;
}
<script src="//cdn.bootcss.com/fabric.js/1.5.0/fabric.js"></script>
<canvas id="c" width="500" height="400"></canvas>
<a id="download">Download as image</a>
Your problem is the multiplier.
When using that kind of clipTo functions, you are setting the transform of canvas to plain. When rendering with canvas with multiplier, the base canvas transformation is scaled by the multiplier.
Your rect will be drawn without this transform ( because of setTransform(1,0,0,1,0,0) and will clip out the image.
Instead of setting the transform to [1,0,0,1,0,0] you should set to the invers of the current transformation of the object you are clipping.
var img01URL = 'https://www.google.com/images/srpr/logo4w.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var canvas = new fabric.Canvas('c');
document.getElementById('download').addEventListener('click', function() {
var data = canvas.toDataURL({
format: 'png',
multiplier: 2
});
console.log(data);
//var img = document.getElementById('export');
//img.src = data;
}, false);
var clipRect1 = new fabric.Rect({
originX: 'left',
originY: 'top',
angle: 90,
left: 195,
top: 0,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
stroke: 'red',
angle: 5
});
var pugImg = new Image();
pugImg.onload = function (img) {
var pug = new fabric.Image(pugImg, {
angle: 0,
width: 500,
height: 500,
left: 245,
top: 35,
scaleX: 0.3,
scaleY: 0.3,
clipName: 'pug',
clipTo: function(ctx) {
ctx.save();
var myMatrix = this.calcTransformMatrix();
myMatrix = fabric.util.invertTransform(myMatrix);
ctx.transform.apply(ctx, myMatrix);
clipRect1.render(ctx);
ctx.restore();
}
});
canvas.add(pug);
};
pugImg.src = img02URL;
#c {
border:0px solid #ccc;
}
<script src="//www.deltalink.it/andreab/fabric/fabric.js"></script>
<canvas id="c" width="500" height="400"></canvas>
<a id="download">Download as image</a>
<img id="export" >

Resources