Pregunta

I am having some trouble with scaling and rotation of SVG images with FabricJS.

I've been working on an icon builder for my website. A user can add layers, select a shape for that layer, then set a number of options such as coloring and stroke width. I populate the possible "shapes" and, for maximum flexibility in the shape's complexity, I am using SVG files that I have created with Inkscape. I use the loadSVGFromURL functionality in FabricJS to handle loading the file onto my canvas.

The problem is when I load some (seems to be most) of these SVGs to the canvas then try to use the handles to scale and rotate the image, the rendered result is not appearing as expected: Octagon SVG Image and Action Results.

On that image, don't worry about the "sliced" edges, that's just the editor's boundaries. After loading my octogon.svg to the canvas, it looks right. When I rotate, it gets messed up. I rotated to the right and downward and the image moved to the left and upward. Then, when I scale, it moves vertically the opposite direction.

I have tried programmatically changing these settings and it behaves the same way. I've read several posted questions here and on newsgroup discussions, but nothing got me a solid solution.

One very close solution was using an optimization tool to remove some transformation data that is apparently not liked much by fabric (that tool being found here http://petercollingridge.appspot.com/). It seemed to work, but not for every image, this one included. In fact, regardless of the optimization options I chose, the tool altered the octagon so much, it wasn't really usable as an octogon. That tool is also reference in this existing question: 10470508 (issue-with-svg-display-rendering-in-fabric-js)

I have saved the SVG out of Inkscape in various formats: Inkscape SVG, plain SVG, and Optimized SVG - none made any difference. I also tried Simplifying the Path prior to exporting in all of these formats - again, no difference (though for some shapes, this did seem to work).

I have read many bugs and the related discussions on GitHub with Kangax involved and tried things like the centeredRotation property and origin points on the objects.

I noticed that Inkscape's x,y of 0,0 is the bottom left corner which I thought was a little odd and thought maybe that had something to do with the scaling at least. To attempt fixing it from that point of view, I set flipY on the object, but that didn't work at all. It appeared very far above the editor panel. It almost feels like the transform point is somewhere way above the bounding box. But I cannot verify that. All the settings I check seem like they are set correctly.

I did try a hexagon made in Illustrator and it seemed to work, but I do not have Illustrator at my disposal and to say that is a "solution" is somewhat undesirable. Perhaps this is better logged as a bug, but with all the related chatter, I am somewhat hoping that it is resolved and I just have not found the right combination of settings or processes to follow. I really need to be able to use Inkscape for these. Kangax has pointed out that Inkscape SVGs are more troublesome for FabricJS, but he goes on to say they are getting better. So perhaps this can help with another step forward.

I have also reviewed the code itself on GitHub, but cannot seem to pin point what exactly I would need to change to fix this; though, I am not really sure where the point of failure is - fabric, my settings, or my SVG file.

UPDATE 2/21/2014 10:27PM EST

I began digging into the SVG file structure, comparing the ones giving me trouble with the ones that are working. It definitely does seem like the problem is due to a "transform" attribute being present on a path, container, or other object tag. The optimization processes I've tried should have removed them, but I still have not found a solid solution that just works in all cases. I'll keep you updated.

¿Fue útil?

Solución 3

Like the other issues posted about this, the problem was still in the individual transformations on the paths. The online solutions I found never worked as well as I needed them to; at least not with SVGs from InkScape. Saving the SVG in a different type right out of InkScape also did not impact the end result. Some shapes, when "simplified", were fine; however, it was not consistent enough. So, I set out to develop a solution.

After reading SVG file structure documentation, I created this specifically to handle InkScape SVGs. Some SVG commands are not handled, but so far, I have not noticed an issue with the few missing commands (which were excluded simply due to time).

EvilEye Games - InkScape SVG Transform Remover

In the end though, I just decided to use some free SVGs from another website. So it was all for not for me. However, I was able to figure it out and fix the problem. So figured maybe this would come in handy for someone else. Its not perfect, but it does what it needs to.

Otros consejos

I don't know much about fabricjs and Inkscape, but using the svg DOM the following will apply for rotation and scale transformations applied individually to an element: Maybe you can apply this. If you want to rotate+scale an element your can append the transformation strings or use transformation matrix. Hope this helps

var bb=elem.getBBox()
var bbx=bb.x
var bby=bb.y
var bbw=bb.width
var bbh=bb.height
var cx=bbx+.5*bbw
var cy=bby+.5*bbh
//----rotate from center of elem---
elem.setAttribute("transform","rotate(angle "+cx+" "+cy+")") 
//---scale: translate center to(0,0)+scale+translate back---
elem.setAttribute("transform","translate("+cx+" "+cy+")scale(myScale)translate("+(-cx)+" "+(-cy+")")

Would it be advantageous to load your svg files as xml using XMLHttpRequest? You could then treat them as xml, work on them, then insert them as SVG by cloning them. pretty seamless, I think. You can extract elements from XMLdoc and insert them as svg by merely cloning them. Also you can include a DIV in your html and dump the entire xml response text into it as its innerHTML. Then everything is available for DOM workings.

var  XMLdoc
function loadSVGasXML()
{
    var SVGFile="my.svg"
    var loadXML = new XMLHttpRequest;
    function handler()
    {
        if(loadXML.readyState == 4 && loadXML.status == 200)
        {
                //---responseText---
                var xmlString=loadXML.responseText
                //---mySVGDiv.innerHTML=xmlString ---
                //---DOMParser---
                var parser = new DOMParser();
                XMLdoc=parser.parseFromString(xmlString,"text/xml").documentElement ;
        }
    }
    if (loadXML != null)
    {
        loadXML.open("GET", SVGFile, true);
        loadXML.onreadystatechange = handler;
        loadXML.send();
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top