diff --git a/src/parser.js b/src/parser.js index 96c333b9..f52df2fe 100644 --- a/src/parser.js +++ b/src/parser.js @@ -468,11 +468,14 @@ viewBoxWidth, viewBoxHeight, matrix, el, widthAttr = element.getAttribute('width'), heightAttr = element.getAttribute('height'), + x = element.getAttribute('x') || 0, + y = element.getAttribute('y') || 0, + preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '', missingViewBox = (!viewBoxAttr || !reViewBoxTagNames.test(element.tagName) || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue))), missingDimAttr = (!widthAttr || !heightAttr || widthAttr === '100%' || heightAttr === '100%'), toBeParsed = missingViewBox && missingDimAttr, - parsedDim = { }; + parsedDim = { }, translateMatrix = ''; parsedDim.width = 0; parsedDim.height = 0; @@ -505,14 +508,21 @@ } // default is to preserve aspect ratio - // preserveAspectRatio attribute to be implemented - scaleY = scaleX = (scaleX > scaleY ? scaleY : scaleX); + preserveAspectRatio = fabric.util.parsePreserveAspectRatioAttribute(preserveAspectRatio); + if (preserveAspectRatio.alignX !== 'none') { + //translate all container for the effect of Mid, Min, Max + scaleY = scaleX = (scaleX > scaleY ? scaleY : scaleX); + } - if (scaleX === 1 && scaleY === 1 && minX === 0 && minY === 0) { + if (scaleX === 1 && scaleY === 1 && minX === 0 && minY === 0 && x === 0 && y === 0) { return parsedDim; } - matrix = ' matrix(' + scaleX + + if (x || y) { + translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') '; + } + + matrix = translateMatrix + ' matrix(' + scaleX + ' 0' + ' 0 ' + scaleY + ' ' + diff --git a/src/shapes/image.class.js b/src/shapes/image.class.js index 6749b452..b4b9495d 100644 --- a/src/shapes/image.class.js +++ b/src/shapes/image.class.js @@ -589,28 +589,13 @@ */ fabric.Image.fromElement = function(element, callback, options) { var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES), - align = 'xMidYMid', meetOrSlice = 'meet', alignX, alignY, aspectRatioAttrs; + preserveAR; if (parsedAttributes.preserveAspectRatio) { - aspectRatioAttrs = parsedAttributes.preserveAspectRatio.split(' '); + preserveAR = fabric.util.parsePreserveAspectRatioAttribute(parsedAttributes.preserveAspectRatio); + extend(parsedAttributes, preserveAR); } - if (aspectRatioAttrs && aspectRatioAttrs.length) { - meetOrSlice = aspectRatioAttrs.pop(); - if (meetOrSlice !== 'meet' && meetOrSlice !== 'slice') { - align = meetOrSlice; - meetOrSlice = 'meet'; - } - else if (aspectRatioAttrs.length) { - align = aspectRatioAttrs.pop(); - } - } - //divide align in alignX and alignY - alignX = align !== 'none' ? align.slice(1, 4) : 'none'; - alignY = align !== 'none' ? align.slice(5, 8) : 'none'; - parsedAttributes.alignX = alignX; - parsedAttributes.alignY = alignY; - parsedAttributes.meetOrSlice = meetOrSlice; fabric.Image.fromURL(parsedAttributes['xlink:href'], callback, extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes)); }; diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index 9cb0b01a..50079d9d 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -1286,6 +1286,7 @@ * @param {Number} [options.r1=0] Radius of start point (only for radial gradients) * @param {Number} [options.r2=0] Radius of end point (only for radial gradients) * @param {Object} [options.colorStops] Color stops object eg. {0: 'ff0000', 1: '000000'} + * @param {Object} [options.gradientTransform] transforMatrix for gradient * @return {fabric.Object} thisArg * @chainable * @see {@link http://jsfiddle.net/fabricjs/58y8b/|jsFiddle demo} @@ -1338,6 +1339,8 @@ gradient.coords.r2 = options.r2; } + options.gradientTransform && (gradient.gradientTransform = options.gradientTransform); + for (var position in options.colorStops) { var color = new fabric.Color(options.colorStops[position]); gradient.colorStops.push({ diff --git a/src/util/misc.js b/src/util/misc.js index 18b832a6..d5c4a23b 100644 --- a/src/util/misc.js +++ b/src/util/misc.js @@ -522,6 +522,35 @@ imageData = null; return _isTransparent; + }, + + /** + * Parse preserveAspectRatio attribute from element + * @param {string} attribute to be parsed + * @return {Object} an object containing align and meetOrSlice attribute + */ + parsePreserveAspectRatioAttribute: function(attribute) { + var meetOrSlice = 'meet', alignX = 'Mid', alignY = 'Mid', + aspectRatioAttrs = attribute.split(' '), align; + + if (aspectRatioAttrs && aspectRatioAttrs.length) { + meetOrSlice = aspectRatioAttrs.pop(); + if (meetOrSlice !== 'meet' && meetOrSlice !== 'slice') { + align = meetOrSlice; + meetOrSlice = 'meet'; + } + else if (aspectRatioAttrs.length) { + align = aspectRatioAttrs.pop(); + } + } + //divide align in alignX and alignY + alignX = align !== 'none' ? align.slice(1, 4) : 'none'; + alignY = align !== 'none' ? align.slice(5, 8) : 'none'; + return { + meetOrSlice: meetOrSlice, + alignX: alignX, + alignY: alignY + }; } }; diff --git a/test/unit/object.js b/test/unit/object.js index ec7cfe20..85aee8b9 100644 --- a/test/unit/object.js +++ b/test/unit/object.js @@ -1067,6 +1067,44 @@ test('toDataURL & reference to canvas', function() { equal(fill.colorStops[1].color, 'rgb(0,128,0)'); }); + test('setGradient with gradientTransform', function() { + var object = new fabric.Object(); + + ok(typeof object.setGradient == 'function'); + + equal(object.setGradient('fill', { + x1: 0, + y1: 0, + x2: 100, + y2: 100, + gradientTransform: [1, 0, 0, 4, 5, 5], + colorStops: { + '0': 'rgb(255,0,0)', + '1': 'rgb(0,128,0)' + } + }), object, 'should be chainable'); + + ok(typeof object.toObject().fill == 'object'); + ok(object.fill instanceof fabric.Gradient); + + var fill = object.fill; + + equal(fill.type, 'linear'); + + equal(fill.coords.x1, 0); + equal(fill.coords.y1, 0); + + equal(fill.coords.x2, 100); + equal(fill.coords.y2, 100); + + deepEqual(fill.gradientTransform, [1, 0, 0, 4, 5, 5]); + + equal(fill.colorStops[0].offset, 0); + equal(fill.colorStops[1].offset, 1); + equal(fill.colorStops[0].color, 'rgb(255,0,0)'); + equal(fill.colorStops[1].color, 'rgb(0,128,0)'); + }); + asyncTest('setPatternFill', function() { var object = new fabric.Object();