Skip to content

Commit

Permalink
added image crop ToSVG support (#4738)
Browse files Browse the repository at this point in the history
* added svg crop support
  • Loading branch information
asturur committed Feb 18, 2018
1 parent 2e532cc commit b47815e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 5 deletions.
28 changes: 23 additions & 5 deletions src/shapes/image.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,24 +280,42 @@
return object;
},

/**
* Returns true if an image has crop applied, inspecting values of cropX,cropY,width,hight.
* @return {Boolean}
*/
hasCrop: function() {
return this.cropX || this.cropY || this.width < this._element.width || this.height < this._element.height;
},

/* _TO_SVG_START_ */
/**
* Returns SVG representation of an instance
* @param {Function} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
*/
toSVG: function(reviver) {
var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2;
var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2, clipPath = '';
if (this.hasCrop()) {
var clipPathId = fabric.Object.__uid++;
markup.push(
'<clipPath id="imageCrop_' + clipPathId + '">\n',
'\t<rect x="' + x + '" y="' + y + '" width="' + this.width + '" height="' + this.height + '" />\n',
'</clipPath>\n'
);
clipPath = ' clip-path="url(#imageCrop_' + clipPathId + ')" ';
}
markup.push('<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n');
var imageMarkup = ['\t<image ', this.getSvgId(), 'xlink:href="', this.getSvgSrc(true),
'" x="', x, '" y="', y,
'" x="', x - this.cropX, '" y="', y - this.cropY,
'" style="', this.getSvgStyles(),
// we're essentially moving origin of transformation from top/left corner to the center of the shape
// by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
// so that object's center aligns with container's left/top
'" width="', this.width,
'" height="', this.height,
'"></image>\n'];
'" width="', this._element.width || this._element.naturalWidth,
'" height="', this._element.height || this._element.height,
'"', clipPath,
'></image>\n'];
if (this.paintFirst === 'fill') {
Array.prototype.push.apply(markup, imageMarkup);
}
Expand Down
33 changes: 33 additions & 0 deletions test/unit/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,39 @@
});
});

QUnit.test('toSVG wit crop', function(assert) {
var done = assert.async();
createImageObject(function(image) {
image.cropX = 1;
image.cropY = 1;
image.width -= 2;
image.height -= 2;
fabric.Object.__uid = 1;
var expectedSVG = '<clipPath id="imageCrop_1">\n\t<rect x="-137" y="-54" width="274" height="108" />\n</clipPath>\n<g transform="translate(137 54)">\n\t<image xlink:href="' + IMG_SRC + '" x="-138" y="-55" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" width="276" height="110" clip-path="url(#imageCrop_1)" ></image>\n</g>\n';
assert.equal(image.toSVG(), expectedSVG);
done();
});
});

QUnit.test('hasCrop', function(assert) {
var done = assert.async();
createImageObject(function(image) {
assert.ok(typeof image.hasCrop === 'function');
assert.equal(image.hasCrop(), false, 'standard image has no crop');
image.cropX = 1;
assert.equal(image.hasCrop(), true, 'cropX !== 0 gives crop true');
image.cropX = 0;
image.cropY = 1;
assert.equal(image.hasCrop(), true, 'cropY !== 0 gives crop true');
image.width -= 1;
assert.equal(image.hasCrop(), true, 'width < element.width gives crop true');
image.width += 1;
image.height -= 1;
assert.equal(image.hasCrop(), true, 'height < element.height gives crop true');
done();
});
});

QUnit.test('toSVG', function(assert) {
var done = assert.async();
createImageObject(function(image) {
Expand Down

0 comments on commit b47815e

Please sign in to comment.