Giu Magnani
Giu Magnani

Reputation: 448

Can't properly import SVGs to canvas

I'm having problems to import SVGs to the canvas and using setZoom() with the FabricJS. I'm using version "2.0.0.rc4".

I've been trying to import them using two methods, but each one has different problems:

1- loadSVGFromURL

fabric.loadSVGFromURL(src, function(objects, options) {
    let loadedObjects = new fabric.Group(group);
    var obj = fabric.util.groupSVGElements(objects, options);
    canvas.add(obj).renderAll();
});

With this method some SVGs load incorrectly on the canvas, but the zoom works perfectly.

loadSVGFromURL loads the SVG incorrectly

2- new fabric.Image

const image = new Image();
image.crossOrigin = "Anonymous";
image.src = src;

let imageObject;

image.onload = () => {
    imageObject = new fabric.Image(image, {
        scaleY: 1,
        scaleX: 1,
        cropX: 0,
        cropY: 0,
        lockUniScaling: true,
        crossOrigin: 'Anonymous'
    });
}

With this method every SVG is correctly imported, but when I try to use the zoom in my app, the shapes of the SVG inside the viewbox (container) adjust their size independently, like it's being masked, cropped or clipped. I guess is something related to the preserveAspectRatio property, but I can't make it work.

This is the method I'm using for setting the zoom. The method works correctly for the canvas and other objects, except the SVGs imported with the method previously described.

setCanvasZoom(value) {
    // value is from 10 to 500.
    // the zoomFactor will result in an integer from 0.1 to 5

    let zoomFactor = parseInt(value, 10) / 100;

    this.canvas.setZoom(zoomFactor);

    this.canvas.setWidth(this.templateDimensions.width * zoomFactor);
    this.canvas.setHeight(this.templateDimensions.height * zoomFactor);

    this.canvas.renderAll();
}

The shapes are adjusted independently to the container

  1. Am I doing something wrong using the first method to import SVGs? I tried optimizing the SVGs with svgo and also edit them in Illustrator but with no success (in fabricjs/kitchensink loads incorrectly as well).

  2. Does exists a way to lock the SVGs inside the container, using the second method? Should I use another method to set the zoom?

I'd really appreciate any help with these issues.

Upvotes: 1

Views: 560

Answers (2)

AndreaBogazzi
AndreaBogazzi

Reputation: 14741

there was indeed a bug in circle and ellipse parsing at the time of writing this question. circles were inheriting width and height from the svg document overriding radius value and displacing them.

The bug has been fixed here, https://github.com/kangax/fabric.js/pull/4637/files#diff-35fc8e842fb0e1e1953d9ba21a292160R189

the bug has been introduced between rc3 and rc4 but now you can import the path normally without preprocessing the SVG, provided you download last version.

Upvotes: 1

Giu Magnani
Giu Magnani

Reputation: 448

The problem was with the SVGs files, the circle tags were imported incorrectly to the FabricJS canvas, placing the objects in other places, even outside the original viewBox.

I tested both versions of the SVG in FabricJS Kitchensink:

Screenshot with the differences between SVG imported with <circle> tags and <circle> tags converted to <paths>

I used svgo to process all the SVGs files with the option of convertShapeToPath included and the parameter convertArcs set as true.

{
  "plugins": [
    {"convertShapeToPath": {"convertArcs": true}},
  ]
}

It's also possible to convert the primitive shapes to paths in Illustrator selecting the object and making a compound path of it (menu Object > Compound path > Create or just cmd ⌘ + 8).

I couldn't find an issue on GitHub or Stack Overflow about this problem, so I really hope this solution could help others facing the same problem.

Thank you very much to the developers and maintainers of FabricJS for the amazing work!

Gists of SVGs files:

SVG with <circle> tags

SVG with <circle> tags converted to <path>

Upvotes: 0

Related Questions