Reputation: 333
I am having a problem saving and loading dynamic patterns that are applied to objects.
I have searched online for a solution to this to no avail. I understand why it is happening, but do not understand how to resolve it.
Here is basically what I am doing...
Everything I have found on this issue dates back to at least 2 years ago (some even 2013), with no solid working example with code.
UPDATE
This is the function I am using to apply patterns on paths...
function applyPatternOnPath(p, image, width, patternRepeat, patternPadding) {
if (patternRepeat) {
var r = 'repeat'
} else {
var r = 'no-repeat'
}
fabric.Image.fromURL(image, function(img) {
var padding = 0 + patternPadding;
img.scaleToWidth(width);
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
patternSourceCanvas.renderAll();
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getScaledWidth() + padding,
height: img.getScaledHeight() + padding
});
patternSourceCanvas.renderAll();
return patternSourceCanvas.getElement();
},
repeat: r
});
p.set('fill', pattern);
canvas.renderAll();
}, { crossOrigin: 'Anonymous' });
}
Upvotes: 1
Views: 1378
Reputation:
Use below code for convert the Image source into the base 64 format and store and reopen the same.
//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: 1
Reputation: 333
I have solved my problem with a little workaround. I am not sure if this is the "correct" way to handle dynamic patterns being saved with JSON but it works for me.
Here's what I am doing...
Right before saving the canvas (JSON string) to MongoDB, I am doing 2 things...
a) Saving the objects information (which include pattern src, width, padding etc.) on one of the fields of the mongoDB document called 'canvasLayers'.
b) Clearing all the 'fill' properties of the paths that have dynamic patterns applied by setting the 'fill' property to "".
So the JSON does not include any pattern information when saved to the DB.
When loading a previously saved canvas, I am re-applying the patterns based on pattern information that was saved on the 'canvasLayers' field for each object.
Basically, I am not saving the pattern info with the JSON string, but rather storing the pattern data on a separate object (mongodb field), and then re-applying the patterns when the canvas loads.
Upvotes: 1