Nick Rameau
Nick Rameau

Reputation: 1318

How to change svg color on Canvas - Fabricjs

I'm creating an app with Fabricjs.
I have to add an SVG file to the canvas and change the color every time a Minicolors input changes.
I first made the browser display the SVG images as SVG codes like so:

$('img[src$=".svg"]').each(function(){
var $img = $(this),
    imgURL = $img.attr('src'),
    attributes = $img.prop('attributes');

$.get(imgURL, function(data) {
  // Get the SVG tag, ignore the rest
  var $svg = $(data).find('svg');
  // Remove any invalid XML tags as per http://validator.w3.org
  $svg = $svg.removeAttr('xmlns:a');
  // Make sure that every attribute was copied
  $.each(attributes, function() {
    $svg.attr(this.name, this.value);
  });
  // Replace image with new SVG
  $img.replaceWith($svg);
}, 'xml');
});

Then I loaded the SVG images from the DOM to the canvas when they get clicked on, like so:

$('#images').on('click', 'svg', function() {
  var serializer = new XMLSerializer(),
  svgStr = serializer.serializeToString(this);

  fabric.loadSVGFromString(svgStr,function(objects, options) {
    options.id = this.id;
    var obj = fabric.util.groupSVGElements(objects, options);

    canvas.add(obj);

    obj.scaleToHeight(127) // Scales it down to some small size
       .scaleToWidth(90)
       .center() // Centers it (no s**t, Sherlock)
       .setCoords();

    canvas.setActiveObject(obj).renderAll();
  });
});

Now for my next goal, how do I change the path color of the selected svg file? My main guess would be to follow these steps:

  1. Save the left and top positions of the selected SVG
  2. Change the color of the SVG image in the DOM
  3. Remove the selected SVG object
  4. Replace it with the new SVG using the new color at the saved left and top positions

But I thought: "So I have to do all this every time a Minicolors input changes? Won't that be a performance issue later?"

Is there a better approach than this? Here's a JSFiddle that will get you started. Thanks.

Upvotes: 5

Views: 8144

Answers (2)

Anuj TBE
Anuj TBE

Reputation: 9790

Answer by Nick Rameau is not working with the latest version of the fabricjs.

In my case, I'm working with fabricjs 3.5.

In the latest version of the fabricjs, the paths attribute has been removed. The paths data has been added to the _objects property.

This is how, I got it working for me.

var obj = this.canvas.itemObj;
var color = '#ff00ff';

if (obj && obj._objects) {
  for (var i = 0; i < obj._objects.length; i++) {
    obj._objects[i].set({
      fill: color
    });
  }
}

Upvotes: 7

Nick Rameau
Nick Rameau

Reputation: 1318

When added to the canvas, the SVG object contains a property called "paths", which contains all the paths that build the image. So we do:

activeObject.paths.forEach(function(path) {path.fill = color});

But I wonder if it won't be a performance issue for huge SVG files (I won't get to that point, hopefully). Here's a working JSFiddle.

Upvotes: 3

Related Questions