Reputation: 61
I am applying pattern to SVG, and using toJSON save data in database. When I am trying to load that on canvas using loadFromJSON its throwing error pattern source is undefined.
Here is my code I am using to set pattern.
fabric.Image.fromURL(url,function(img){
img.scaleToWidth(width);
if (angle > 0) img.set('angle', angle);
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
patternSourceCanvas.renderAll();
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width:img.getWidth() + padding,
height:img.getHeight() + padding
});
patternSourceCanvas.renderAll();
return patternSourceCanvas.getElement();
},
repeat: isrepeat,
src: url,
});
if(left_offset > 0) { pattern.offsetX = (left_offset); } else{ pattern.offsetX = 0;}
if(top_offset > 0) { pattern.offsetY = (top_offset); } else { pattern.offsetY = 0;}
var applyPatternto = 0;
if(activeView != 1){ applyPatternto = $("#sel_applyPatternto").val(); }
currentElement.paths[applyPatternto].setFill(pattern);
canvas.renderAll();
});
to load save JSON and load from JSON I am using following,
var frontJson = JSON.stringify(canvas.toJSON());
while loading from JSON I also add delay to check same issue,
canvas.loadFromJSON(frontJson);
setTimeout(function(){
canvas.renderAll.bind(canvas);
},3000);
Upvotes: 0
Views: 966
Reputation:
Use below code for convert the Image source into the base 64 format and store in database and reopen the same.
JavaScript:
//override toObject of fabric.Pattern
var toFixed = fabric.util.toFixed;
fabric.Pattern.prototype.toObject = function(propertiesToInclude) {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
source, object;
if (typeof this.source === "function") {
source = String(this.source);
} else if (typeof this.source.src === "string") {
source = this.source.src;
} else if (typeof this.source === "object" && this.source.toDataURL) {
source = this.source.toDataURL();
}
object = {
type: "pattern",
source: source,
repeat: this.repeat,
crossOrigin: this.crossOrigin,
offsetX: toFixed(this.offsetX, NUM_FRACTION_DIGITS),
offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS),
patternTransform: this.patternTransform ? this.patternTransform.concat() : null
};
fabric.util.populateWithProperties(this, object, propertiesToInclude);
return object;
};
var imageUrl = 'https://upload.wikimedia.org/wikipedia/commons/2/22/Wikimapia_logotype.svg';
var canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
width: 200,
height: 200,
strokeWidth: 2,
stroke: '#000'
})
canvas.add(rect);
fabric.Image.fromURL(imageUrl, function(img) {
//alert('t' + img);
console.log('img', img);
img.scaleToHeight(200);
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
patternSourceCanvas.setDimensions({
width: img.getWidth(),
height: img.getHeight()
});
patternSourceCanvas.renderAll();
var pattern = new fabric.Pattern({
source: patternSourceCanvas.getElement()
});
rect.fill = pattern;
canvas.renderAll();
}, {
crossOrigin: 'annonymous'
});
$('#loadjson').on('click', function() {
var json = canvas.toJSON();
console.log('json', json['objects']);
canvas.clear();
setTimeout(function() {
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));
}, 3000)
})
css:
canvas{
border:2px solid #000;
}
Html:
<canvas id="canvas" width="300" height="300"></canvas><br>
<button id="loadjson">loadfromjson </button>
<script src='https://www.multicastr.com/imageeditor/assets/js/fabric.unmin.js'></script>
<script src="https://www.multicastr.com/user/js/jquery.min.js"></script>
Upvotes: 0
Reputation: 14741
Is scope problem.
You can't reload a function from JSON that has references outside of itself.
When the function gets rebuilded there is no patternSourceCanvas defined for it to run.
source: function() {
patternSourceCanvas.setDimensions({
width:img.getWidth() + padding,
height:img.getHeight() + padding
});
patternSourceCanvas.renderAll();
return patternSourceCanvas.getElement();
},
in this context patternSourceCanvas is undefined.
Even if you provide the patternSourceCanvas internally that would be helpless since the img will not be painted on it.
If you need to build a pattern with a function you have to be sure that those vars are available in the global namespace at render time.
is also unclear where padding comes from, it may be affected from the same problem.
Upvotes: 2