I solved this issue in my app by having two Canvas areas on the page. In my case I named the first one "prep" and the actual drawing area one "stage"
<div class="col-sm-2">
<canvas id="prep" width="150" height="500" style= "border: 1px solid #d3d3d3;"></canvas>
</div>
<div class="col-sm-10">
<canvas id="stage" width="650" height="500" style="border: 1px solid #d3d3d3;"></canvas>
</div>
Then, I added a mouse:down event to the prep area. If a shape is clicked in the 'prep' area, a cloned object gets added to the 'stage' area.
prep.on('mouse:down', function(options){
if(options.target) {
if (fabric.util.getKlass(options.target.type).async) {
console.log('entered')
options.target.clone(function (clone) {
clone.set({left: 200, top: 100});
stage.add(clone);
});
}
else {
stage.add(options.target.clone().set({left: 100, top: 100}));
}
}
});
When you initialize the shapes to put on the prep area, you can make them selectable:false. In my app, the selectable:false didn't get transferred during the clone (not sure if it was a mistake in my code) - you can also change the properties during clone.
Note - the if(...async) portion of the code is to deal with the fact that I have both SVG and normal shapes in the prep area. If you only have standard fabric shapes, you only need the code contained in the else statement.