Having difficulty importing SVG files into the canvas

I'm encountering difficulties when attempting to import SVGs to the canvas and use setZoom() with FabricJS. I am currently working with version "2.0.0.rc4".

I have made attempts to import them using two different methods, each with its own set of challenges:

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();
});

While this method successfully loads some SVGs onto the canvas, there are instances where the SVGs are displayed incorrectly. However, the zoom function works flawlessly.

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'
    });
}

Using this method, every SVG is imported correctly. However, when I attempt to zoom in my application, the shapes of the SVGs within the viewbox/container adjust their size independently, appearing cropped or clipped. This issue may be related to the preserveAspectRatio property, but I have been unable to resolve it.

The zoom function I am utilizing is as follows. While it works effectively for the canvas and other objects, it does not produce the desired outcome for the SVGs imported using the previous method.

setCanvasZoom(value) {
    // value ranges from 10 to 500.
    // the zoomFactor will range 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. Could there be a mistake in how I am using the first method to import SVGs? I have attempted optimizing the SVGs with svgo and editing them in Illustrator without success (the issue also persists in fabricjs/kitchensink).

  2. Is there a way to confine the SVGs within the container using the second method? Should a different approach be taken with setting the zoom?

Any assistance with these challenges would be greatly appreciated.

Answer №1

During the time this question was written, there was a known bug with how circles and ellipses were parsed. Circles were mistakenly inheriting width and height values from the SVG document, which was causing the radius value to be overridden and displaced.

Fortunately, the bug has since been fixed. You can find more information about the fix here.

This issue cropped up between versions rc3 and rc4, but now you can import paths as usual without needing to preprocess the SVG, as long as you have the latest version downloaded.

Answer №2

The issue stemmed from incorrect import of circle tags in the SVG files into the FabricJS canvas, causing the objects to be placed in incorrect positions, sometimes even outside the original viewBox.

Both versions of the SVG were tested in FabricJS Kitchensink:

View the screenshot highlighting the variances between the SVG imported with <circle> tags and the one with <circle> tags converted to <paths>

Utilizing svgo, all SVG files were processed with the option of convertShapeToPath enabled and the parameter convertArcs set to true.

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

In Illustrator, primitive shapes can also be converted to paths by selecting the object and creating a compound path from it (menu Object > Compound path > Create or cmd ⌘ + 8).

Despite not finding any reported issues on GitHub or Stack Overflow regarding this particular problem, I hope this solution can assist others encountering similar challenges.

Special thanks to the dedicated developers and maintainers of FabricJS for their exceptional contributions!

Links to SVG files:

SVG with <circle> tags

SVG with <circle> tags converted to <path>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Capture user input to extract data from a JavaScript object

I need help with implementing a search function where users can enter a name and the person's extension will be displayed on the UI either by clicking a button or pressing "return". Any ideas on how to make this feature work seamlessly? UI <html ...

Using the && operator in an if statement along with checking the length property

Why does the console show 'Cannot read property 'length' of undefined' error message when I merge two if conditions together? //When combining two if statements using &&: for(n= 0, len=i.length; n<len; n++) { if(typeof ...

Using a combination of Javascript and PHP to dynamically update the innerHTML of multiple elements

I am working on updating the innerHTML of a webpage using Javascript after an onclick event. In my java.js file, I am utilizing this code to access a PHP page that echoes back the text for updating the innerHTML. The issue arises when attempting to update ...

Node.js and react-create-app are not compatible with each other

I am currently using node.js version 14.6.0 and node-v version 7.20.0 To replicate the issue, follow these steps: npx create-react-app my-app2 Once everything is installed, run npm i After completing the above steps, you may encounter the following warn ...

Learn the technique in Vue to separate a string using commas and store the values in an array

As a Ruby enthusiast, I am delving into the world of Vue. In my project, users can input multiple styleCodes separated by commas. I aim to store these styleCodes in an array for flexible length calculations. See my code snippet below: <template> &l ...

The compilation of the module has encountered an error with the PostCSS loader. There is a SyntaxError at line 2, character 14 indicating an unknown

I am developing an Angular 8 application. Currently, I am incorporating AlertifyJs into my project. In the styles.css file of Angular, I have imported these libraries: @import '../node_modules/alertifyjs/build/alertify.min.js'; @import '. ...

Using the Object.assign technique will modify the original object's properties in JavaScript

Recently delving into ReactJS, I stumbled upon an interesting revelation regarding the Object.assign() method: const B = { k1: 'b', k2: 'bb', treedata: [{ children: ['g'] }] } var A = Object.assign( ...

Exploring the methods for monitoring multiple UDP ports on a single address in Node.js within a single process

I am currently working on developing a Node.js application to manage a small drone. The SDK provides the following instructions: To establish a connection between the Tello and a PC, Mac, or mobile device, use Wi-Fi. Sending Commands & Receiving Responses ...

I am facing an issue with the DOM object in my ejs template when used under the script tag. How can I resolve this problem?

<%-include ("partials/header.ejs") %> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <header> <!--NAVIGATION BAR--> <img class="calender-pic" src="images/calendar.png ...

Invoking a function passed via props that utilizes react-router's features

I'm really struggling to grasp this problem. Is there anyone here who could help me out? I have a component where I pass a method called this.fetchContent as props named Filter. This method triggers an action creator that uses axios with Redux to fetc ...

Leap over in a similar fashion to the provided demonstration

In my attempt to create a unique project, I have created this CodePen example. The goal is to have one ball on the circle that remains in a fixed position, while another rotating main ball must avoid touching it at all costs. Points are awarded for success ...

Error: The class constructor [] must be called with the 'new' keyword when creating instances in a Vite project

I encountered an issue in my small Vue 3 project set up with Vite where I received the error message Class constructor XX cannot be invoked without 'new'. After researching online, it seems that this problem typically arises when a transpiled cla ...

Determine if an option is chosen in multiple select elements using Vanilla JavaScript

In order to determine if a checkbox is checked, we use the following code: let isChecked = event.target.checked But what about multiple select options like the example below? <select name="books[]" multiple> <option value="A">A</option& ...

Is there a way to trigger a Tab key click event while typing in a text field?

Can you show me how to capture the Tab key event in jQuery? I want to display an alert if a user clicks the Tab key while entering text in an input field. I have tried using the following code but it's not working... var myInput = document.getEleme ...

streamlined method for accessing page parameters in nested components using the next.js application router

In my next.js application, I have a deep hierarchy of nested components. I currently use the params.lang parameter for translations, but I find myself passing it down to every nested component. Although there are hooks available, I prefer rendering them ...

`The challenge of properly handling quotation marks within quotation marks in JavaScript string literals

I am having trouble displaying text in a JavaScript tooltip Despite my efforts to escape the quotes and eliminate any line breaks, I keep encountering unterminated string literals. The specific text I want to show is: "No, we can't. This is going t ...

"I'm trying to incorporate react-datepicker into my ReScript application, but I'm struggling to

I am attempting to incorporate an external library like react-datepicker into my project. Below is the code snippet and how I am using it: module DatePicker = { @react.component @module("react-datepicker") external make: () => React.eleme ...

What is the best way to combine data from two rows into one row?

Can someone help me with merging 2 sets of Line data into a single row for each entry? For example, the 'Green Bay Packers @ Chicago Bears' row should display '+3.5000 and -3.5000', while 'Atlanta @ Minnesota' should show &apo ...

Implement a Basic Custom Shader on a Cube in Three.js

Struggling with applying a basic custom shader to a cube in Three.js. Whenever I attempt to use the shader, the cube mysteriously vanishes. No issues when using a standard Toon or Lambert Material - cube rotates and behaves as expected. Oddly, Orbit Contr ...

Step-by-step guide for integrating a Twig file in Symfony using Angular's ng-include feature

Seeking guidance in Angular, as a newcomer to the platform. I attempted to load a template within an ng-repeat loop like so, but encountered an error. I received the following error message: "Cross origin requests are only supported for protocol schemes ...