Open Siyfion opened 10 years ago
Ok, so I fixed few things.
"visibility: hidden" should now be working. Text is now positioned slightly better, but not exactly correct yet. We need to add support for "text-anchor" which isn't straightforward.
I'll be looking into it more.
Hi,
I write this code to start to manage tspan position x/y :
fabric.Text.positionFromTspan = function(element, options) {
var position = {
x: 0,
y: 0
};
var childrens = [].slice.call(element.childNodes);
var tspans = new Array();
childrens.forEach(function(el, index, array) {
if (el.nodeName == 'tspan') {
tspans.push(el);
}
});
if (tspans.length > 0) {
var tspan = tspans[0];
var attributes = [].slice.call(tspan.attributes);
attributes.forEach(function(attr, index, array) {
if (attr.nodeName == 'x') {
position.x = parseFloat(attr.nodeValue);
} else if (attr.nodeName == 'y') {
position.y = parseFloat(attr.nodeValue);
}
});
return position;
} else {
return undefined;
}
};
/**
* Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)
* @static
* @memberOf fabric.Text
* @param {SVGElement} element Element to parse
* @param {Object} [options] Options object
* @return {fabric.Text} Instance of fabric.Text
*/
fabric.Text.fromElement = function(element, options) {
if (!element) {
return null;
}
var parsedAttributes = fabric.parseAttributes(element, fabric.Text.ATTRIBUTE_NAMES);
options = fabric.util.object.extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes);
// TSPAN :
var position = this.positionFromTspan(element, options);
if (position != undefined) {
options.top = position.y;
options.left = position.x;
} else {
options.top = options.top || 0;
options.left = options.left || 0;
}
if ('dx' in parsedAttributes) {
options.left += parsedAttributes.dx;
}
if ('dy' in parsedAttributes) {
options.top += parsedAttributes.dy;
}
if (!('fontSize' in options)) {
options.fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;
}
if (!options.originX) {
options.originX = 'left';
}
var textContent = element.textContent.replace(/^\s+|\s+$|\n+/g, '').replace(/\s+/g, ' '),
text = new fabric.Text(textContent, options),
/*
Adjust positioning:
x/y attributes in SVG correspond to the bottom-left corner of text bounding box
top/left properties in Fabric correspond to center point of text bounding box
*/
offX = 0;
if (text.originX === 'left') {
offX = text.getWidth() / 2;
}
if (text.originX === 'right') {
offX = -text.getWidth() / 2;
}
text.set({
left: text.getLeft() + offX,
top: text.getTop() - text.getHeight() / 2 + text.fontSize * (0.18 + text._fontSizeFraction) /* 0.3 is the old lineHeight */
});
return text;
};
I closed #820 but we should just not forget to account for rotate attribute on tspans
Hi guys,
I'm really straggling with this issue, I'm creating an editor and it's very important to have the ability to save and load back for edit exactly as it was edited, that's proven to be difficult when importing back from svg it re position text elements, is there any clean fix/workaround for this? it's becoming crucial whether or not keep using this approach if no solution will be found.
Thanks!
can t you just use json for exporting and reimporting? svg is not meant for that
Wondering about this issue - any possible workarounds related to how the .SVG is initially constructed/saved? Great library thanks
Hello,
@asturur you are suggesting to use json for exporting and importing, but what if we need to create an export pdf file ? I am using both exporting formats: 1. SVG - for PDF export 2. JSON for later import in canvas. But now I have encountered an issue with updating text in SVG. For text objects I am using texbox as I need text-wrapping. The thing is that after export in SVG each letter is kept in separate tspan with its own styling. But later when I want to update that text (for example some tranbsaltion key ahs been added to canvas and before export to pdf I want to change that key with real translated value) I don't know what styling to apply to tspans. So my question mainly is how fabirc is calculating styling for tspans position, etc. Or is there other way to update text in exported svg without loosing styling and avoiding tspans styling calculation ?
Thanks in advance
there is not. Svg is pretty much an image with POOR text support.
you could make a trick, modify the svg export, add an attribute to text object with a json stringfy of the style object, and make some custom code when reimport it.
not something i want to support.
i want to do proper TSPAN support but i did not start yet
Maybe i understood bad. what styling are you talking about? color, font, size?
@asturur first of all thanks for your very quick response.
My main problem is that pdf export is done via cron job, when editor is closed. So I can't export svg directly from canvas. I am taking svg from DB and tryng to translate it before export.
So now about stylings mentioned in above comment: I am talking about the style of each tspan element. When we export canvas to svg each letter of canvas text object is kept in separate "<tspan x="-100" y="7.87" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: ; opacity: 1;">#</tspan>
So for translating SVG I need to replace '#' to 'Hello' which means that above tspan(s) list should be changed to new tspan list containing letters for 'Hello' (Means that 1 tspan should be replaced with 5 tspans). Well for 1st tspans can be kept the same x, y, style (but maybe even this can not be kept, as if I have translated 2nd letter bigger/smaller than trasnaltion key letter than might be that x coordinate should be changed as well), but what about other new tspans. The problem is that I don't know what x, y, style to apply for each letter of "Hello". I guess as for styling I can take translation keys last letter style for all other newer elements, but what about x, y position. This is my main problem. So the question can be rephrased so how x, y attribute values are calculated for each tspan based on letter that it contains. Or in general how a text can be changed with other text in SVG without loosing any information about its styling.
Actually I was doing translation of SVG without taking into account tspan at all. Just each text ndoeValue was changed $text->nodeValue = $translatedText (Please refer to below translateTemplateSVG ). BUt then I realised that with this approach text alignments are lost (left, right, center), so I came to an idea that tspans should be kept to have everything working as they supposed to.
static public function translateTemplateSVG($svg) {
$doc = new DOMDocument();
$doc->loadXML($svg);
$texts = $doc->getElementsByTagName('text');
if(!$texts){
return $svg;
}
foreach ($texts as $text) {
$currentText = preg_replace('/\s+/', '', $text->nodeValue);
$traslatedText = self::translateText($currentText);
if($traslatedText){
$text->nodeValue = $traslatedText;
}
}
return $doc->saveXML();
}
Looking forward to hear from you soon.
Hello @asturur; I was curious if there is any future plan for implementing tspan
support for multiline text importing. I see it was removed from the 2.0.0
milestone. :(
clippath is priority and masks. tspan support has started with the vertical offset that is ready in a branch and unmerged.
Thanks @asturur! Mind sharing the branch that has the changes for handling the vertical offset. Didn't see it in the stale or active branches. Apologies if it is mixed in with other branches and I just didn't look hard enough. Thanks for your work on this project!
is in the branch list, is there. search for superscrit or subscript
On 21 Dec 2017 21:13, "Seth Messer" notifications@github.com wrote:
Thanks @asturur https://github.com/asturur! Mind sharing the branch that has the changes for handling the vertical offset. Didn't see it in the stale or active branches. Apologies if it is mixed in with other branches and I just didn't look hard enough. Thanks for your work on this project!
ā You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/kangax/fabric.js/issues/1280#issuecomment-353447070, or mute the thread https://github.com/notifications/unsubscribe-auth/ABI4QKS99LBhcG8XhL4XmE5dr06hLJfWks5tCrwEgaJpZM4Bysv3 .
baseline-shift is the name. but it does not contain much about tspan yet
On 21 Dec 2017 21:20, "Andrea Bogazzi" andreabogazzi79@gmail.com wrote:
is in the branch list, is there. search for superscrit or subscript
On 21 Dec 2017 21:13, "Seth Messer" notifications@github.com wrote:
Thanks @asturur https://github.com/asturur! Mind sharing the branch that has the changes for handling the vertical offset. Didn't see it in the stale or active branches. Apologies if it is mixed in with other branches and I just didn't look hard enough. Thanks for your work on this project!
ā You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/kangax/fabric.js/issues/1280#issuecomment-353447070, or mute the thread https://github.com/notifications/unsubscribe-auth/ABI4QKS99LBhcG8XhL4XmE5dr06hLJfWks5tCrwEgaJpZM4Bysv3 .
Thanks so much @asturur; If y'all have any ideas/details around what you were wanting to see happen with that, I'd be happy to work on it in that baseline-shift
branch or in a new branch. It's a pretty important capability for what I'm working on, so I'd for sure be available to work on implementing that feature, at least to some basic degree. Thanks and let me know! Have a great day and Christmas/holiday season if I don't hear back from you.
well if you want to research on it, we still need parsing of text element, preserving the tspan properties for each text chunk and also the dx and dy attribute of tspans can be in written in many different ways and they need to be parsed as well.
tspan that look like different text lines will probably not be different text lines of the same text. will likely be different fabricjs texts.
On 21 Dec 2017 21:28, "Seth Messer" notifications@github.com wrote:
Thanks so much @asturur https://github.com/asturur; If y'all have any ideas/details around what you were wanting to see happen with that, I'd be happy to work on it in that baseline-shift branch or in a new branch. It's a pretty important capability for what I'm working on, so I'd for sure be available to work on implementing that feature, at least to some basic degree. Thanks and let me know! Have a great day and Christmas/holiday season if I don't hear back from you.
ā You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/kangax/fabric.js/issues/1280#issuecomment-353450150, or mute the thread https://github.com/notifications/unsubscribe-auth/ABI4QOyVBOpHz6stmMD2TTZPoaAQz1qZks5tCr98gaJpZM4Bysv3 .
Isn't it possible to just remove the tspan from the text elements, as a workaround ? Like, in the reviver method ?
Tspans are removed indeed, but positions and different styles are lost.
Good afternoon friends I had the same problem to position the tspan with the loadSVGFromString method, I noticed that creating by itext and passing the text configuration parameters the position is more accurate. So far I have managed to position it as in the following example codepen but want to achieve a more exact position. I have tried different methods but as far as Tspan still has no support in the versions of fabricjs
I change the fabrics.js š https://github.com/haki9/fabric.js/commit/6d049ed0954ac08b7cd927975ca500e6ddd4fd0b
And code javascript:
fabric.loadSVGFromURL(url, function (
objects,
options,
elements,
allElements
) {
objects.forEach(function (obj, index) {
if (obj["type"] == "image") {
if (obj["id"].toUpperCase() == "BACKGROUND") {
fabric.Image.fromURL(obj['xlink:href'], function (img) {
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));
});
} else {
obj.set({
selectable: true,
evented: true
});
canvas.add(obj).renderAll();
}
} else if (obj["type"] == "text") {
var element = elements[index];
var childrens = [].slice.call(element.childNodes);
var value = "";
childrens.forEach(function (el, index, array) {
if (el.nodeName == "tspan") {
value += el.childNodes[0].nodeValue;
} else if (el.nodeName == "#text") {
value += el.nodeValue;
}
if (index < childrens.length - 1) {
value += "\n";
}
});
value =
obj["text-transform"] == "uppercase"
? value.toUpperCase()
: value;
var text = new fabric.IText(obj.text, obj.toObject());
text.set({
text: value,
type: 'i-text'
});
var left = 0;
var _textAlign = obj.get("textAnchor")
? obj.get("textAnchor")
: "left";
switch (_textAlign) {
case "center":
left = obj.left - text.getScaledWidth() / 2;
break;
case "right":
left = obj.left - text.getScaledWidth();
break;
default:
left = obj.left;
break;
}
text.set({
left: left,
textAlign: _textAlign
});
canvas.add(text).renderAll();
} else {
canvas.add(obj).renderAll();
}
});
canvas.setWidth(options.width);
canvas.setHeight(options.height);
canvas.calcOffset();
And this is SVG file for testing: https://drive.google.com/open?id=1laXzM0SyK1URzHVy9blCFeBDcaWlV78P
@haki9 I used your method, it works just fine for styling, but as soon as I put multiple lines in my text, the top positioning of the text gets messed up.
Any updated with this?
No, no one worked on it.
Any updates with this??
no zero, zero. Although with dx,dy support we have someone could try to implement it. A new svg parser would make things easeir
@asturur Something new nowadays or any alternatives?
No, not at all. I ll probably get it done after i made curved text better and after i improved the masks pr
Hi @asturur, is it fixable. any workaround ?
@asturur any update regarding ### TSpan working in SVG?
no one right now has time to work on this
@asturur is there a solution? I am trying to load an SVG file with tspans and the text gets rendered much too large
I just added a bounty of 200$ on this open bug. Maybe others can join as well, as there seem to be multiple people interested in a fix.
https://app.bountysource.com/issues/1676489-tspan-support
I created the following smaller testcase, with some texts of different sizes and guidelines, which makes it easy to check the results. It was created with Inkscape and optimized for better readability with svgo
@bluegaspode Maybe something like this? I just did it quickly and didnt really flush out everything.. but just wanted to see.
For the given example it works already, thats cool!
I have a second example, with just 4 aligned text-blocks, where it doesn't work though :( Again it was created with Inkscape and optimized via svgo and I don't see any strong specialties in the markup.
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="100" id="svg4136" version="1.1">
<g id="layer1">
<text xml:space="preserve" style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="30" y="55" id="text4933"><tspan id="tspan4935" x="30" y="55" style="font-size:15px;line-height:1.25">Ā </tspan></text>
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="100.129" y="36" id="text4969"><tspan id="tspan4971" x="100.129" y="36" style="font-size:12.5px;line-height:1.25">###LINE2</tspan><tspan x="100.129" y="52" id="tspan4992" style="font-size:12.5px;line-height:1.25">###LINE3</tspan></text>
<rect style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.59996504;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4994" width="200.12" height="279.7" x="0" y="0" ry=".337"/>
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="100.129" y="18" id="text4996"><tspan id="tspan4998" x="100.129" y="18" style="font-size:12.5px;line-height:1.25">###LINE1</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="99.717" y="71" id="text4996-5"><tspan id="tspan4998-9" x="99.717" y="71.508" style="font-size:10px;line-height:1.25">###KNX</tspan></text>
<path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.6;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" d="M0 60.275h200" id="path4200"/>
<path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.60000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M0 75h200" id="path4200-8"/>
</g>
</svg>
target image should look like this (you can check with a browser or Inkscape)
with the given jsfiddle looks like this:
Once it works with the callback for fabric it would be great to see it as a pull request to fabric.js library, i.e. extending the loadSVGFromString function to support tspans 'natively'.
Any update on this?
Any update on this?
no we are busy with other tasks sadly and we didn't do any new feature development
but if anyone wants to PR I can back them
@gloriousjob @more-strive
Did you find any alternative solution to import a simple svg with correctly aligned text?
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="637" height="1012" viewBox="305.5 50 637 1012" xml:space="preserve">
<desc>Created with Fabric.js 5.3.0</desc>
<defs>
</defs>
<g transform="matrix(1 0 0 1 624.5 556.5)" id="stage">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1;" x="-318.5" y="-506" rx="0" ry="0" width="637" height="1012"/>
</g>
<g transform="matrix(6.49 0 0 10.53 628.5 566.91)" id="rect-001pu2rkl">
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(135,216,203); fill-rule: nonzero; opacity: 1;" x="-49.5" y="-49.5" rx="0" ry="0" width="99" height="99"/>
</g>
<g transform="matrix(6.66 0 0 6.66 486.08 127.53)" style="" id="itext-001k23wx5">
<text xml:space="preserve" font-family="Calibri" font-size="20" font-style="normal" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(254,254,254); fill-rule: nonzero; opacity: 1; white-space: pre;"><tspan x="-21.69" y="6.28">Texto</tspan></text>
</g>
</svg>
Most of my files are in PDF and PSD formats, and now they are parsed directly into JSON as templates
Github: https://github.com/dromara/yft-design
demo: https://yft.design
Of course, there are still some bugs, but there are no issues with parsing the content
@more-strive I accessed your demo, and saw that it has PDF and CDR import, how did you manage to implement the conversion from PDF/CDR to the fabic.js json format?
I managed to implement export to PDF, exporting from fabic.js to svg and adding it to the PDF via jsPDF
PDF is parsed through pymupdf, but CDR has not yet implemented parsing
Github: https://githubfast.com/dromara/yft-design
Any Update on this? Or any workaround to get the correct left and top values for text elements when importing the svg to canvas?
Hey @developersgit this is a long standing feature i was planning to take up again now that 6.0 is stable. This one, svg masks, single object rendering, text on a path, and canvas rotation i think were the long standing one. I still need to write some basic docs for 6.0 before going on more development work
I found the workaround for text
tag shifting , this caused by the object from loadSVGFromString
func being flattened,
but when the text
tag that has tspan
child going to flattened, the tspan
attributes are not being calculated, especially attributes that control the left and top pos (in this case x,y
attributes),
so, for the workaround:
loadSVGFromString(reader.result as string).then((output) => {
const {objects, elements} = output
objects.forEach((obj, index) => {
if (obj && obj.type === 'text') {
const currentElement = elements[index]
if (currentElement.children.length > 0 && currentElement.children[0].tagName === 'tspan') {
const tspan = currentElement.children[0]
// @ts-expect-error; TODO: define tspan types properly
const { x, y } = tspan.attributes
// THE FIX: Update x and y position of text object
obj.left += Number(x.value)
obj.top += Number(y.value)
}
// @ts-expect-error; TODO: define obj types properly
const text = new Textbox(obj.text, {
...obj,
snapAngle: 45,
snapThreshold: 1,
editable: true,
})
return canvas?.add(text);
}
obj && canvas?.add(obj);
})
})
hope this helps
So these issues all relate to the
fabric.loadSVGFromString
method, when given a string such as:Which given the SVG rendered here:
Produces the following output:
Which is doing several things wrong:
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.