mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-04-18 21:20:59 +00:00
fix gradient toSVG for radial gradients (#3807)
* support svg crossorigin on images * fix gradient export * added tests
This commit is contained in:
parent
e4a42e054f
commit
f877f52f2a
3 changed files with 104 additions and 17 deletions
|
|
@ -135,7 +135,7 @@
|
|||
for (var position in colorStops) {
|
||||
var color = new fabric.Color(colorStops[position]);
|
||||
this.colorStops.push({
|
||||
offset: position,
|
||||
offset: parseFloat(position),
|
||||
color: color.toRgb(),
|
||||
opacity: color.getAlpha()
|
||||
});
|
||||
|
|
@ -170,8 +170,8 @@
|
|||
*/
|
||||
toSVG: function(object) {
|
||||
var coords = fabric.util.object.clone(this.coords),
|
||||
markup, commonAttributes;
|
||||
|
||||
markup, commonAttributes, colorStops = this.colorStops,
|
||||
needsSwap = coords.r1 > coords.r2;
|
||||
// colorStops must be sorted ascending
|
||||
this.colorStops.sort(function(a, b) {
|
||||
return a.offset - b.offset;
|
||||
|
|
@ -179,7 +179,7 @@
|
|||
|
||||
if (!(object.group && object.group.type === 'path-group')) {
|
||||
for (var prop in coords) {
|
||||
if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
|
||||
if (prop === 'x1' || prop === 'x2') {
|
||||
coords[prop] += this.offsetX - object.width / 2;
|
||||
}
|
||||
else if (prop === 'y1' || prop === 'y2') {
|
||||
|
|
@ -205,24 +205,45 @@
|
|||
];
|
||||
}
|
||||
else if (this.type === 'radial') {
|
||||
// svg radial gradient has just 1 radius. the biggest.
|
||||
markup = [
|
||||
'<radialGradient ',
|
||||
commonAttributes,
|
||||
' cx="', coords.x2,
|
||||
'" cy="', coords.y2,
|
||||
'" r="', coords.r2,
|
||||
'" fx="', coords.x1,
|
||||
'" fy="', coords.y1,
|
||||
' cx="', needsSwap ? coords.x1 : coords.x2,
|
||||
'" cy="', needsSwap ? coords.y1 : coords.y2,
|
||||
'" r="', needsSwap ? coords.r1 : coords.r2,
|
||||
'" fx="', needsSwap ? coords.x2 : coords.x1,
|
||||
'" fy="', needsSwap ? coords.y2 : coords.y1,
|
||||
'">\n'
|
||||
];
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.colorStops.length; i++) {
|
||||
if (this.type === 'radial') {
|
||||
if (needsSwap) {
|
||||
// svg goes from internal to external radius. if radius are inverted, swap color stops.
|
||||
colorStops = colorStops.concat().reverse();
|
||||
for (var i = 0; i < colorStops.length; i++) {
|
||||
colorStops[i].offset = 1 - colorStops[i].offset;
|
||||
}
|
||||
}
|
||||
var minRadius = Math.min(coords.r1, coords.r2);
|
||||
if (minRadius > 0) {
|
||||
// i have to shift all colorStops and add new one in 0.
|
||||
var maxRadius = Math.max(coords.r1, coords.r2),
|
||||
percentageShift = minRadius / maxRadius;
|
||||
for (var i = 0; i < colorStops.length; i++) {
|
||||
colorStops[i].offset += percentageShift * (1 - colorStops[i].offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < colorStops.length; i++) {
|
||||
var colorStop = colorStops[i];
|
||||
markup.push(
|
||||
'<stop ',
|
||||
'offset="', (this.colorStops[i].offset * 100) + '%',
|
||||
'" style="stop-color:', this.colorStops[i].color,
|
||||
(this.colorStops[i].opacity !== null ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),
|
||||
'offset="', (colorStop.offset * 100) + '%',
|
||||
'" style="stop-color:', colorStop.color,
|
||||
(colorStop.opacity !== null ? ';stop-opacity: ' + colorStop.opacity : ';'),
|
||||
'"/>\n'
|
||||
);
|
||||
}
|
||||
|
|
@ -274,7 +295,7 @@
|
|||
if (typeof opacity !== 'undefined') {
|
||||
color = new fabric.Color(color).setAlpha(opacity).toRgba();
|
||||
}
|
||||
gradient.addColorStop(parseFloat(offset), color);
|
||||
gradient.addColorStop(offset, color);
|
||||
}
|
||||
|
||||
return gradient;
|
||||
|
|
|
|||
|
|
@ -615,7 +615,7 @@
|
|||
var svgUid = fabric.Object.__uid++,
|
||||
options = applyViewboxTransform(doc),
|
||||
descendants = fabric.util.toArray(doc.getElementsByTagName('*'));
|
||||
options.crossOrigin = parsingOptions.crossOrigin;
|
||||
options.crossOrigin = parsingOptions && parsingOptions.crossOrigin;
|
||||
options.svgUid = svgUid;
|
||||
|
||||
if (descendants.length === 0 && fabric.isLikelyNode) {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,47 @@
|
|||
});
|
||||
}
|
||||
|
||||
function createRadialGradientWithInternalRadius() {
|
||||
return new fabric.Gradient({
|
||||
type: 'radial',
|
||||
coords: {
|
||||
x1: 0,
|
||||
y1: 10,
|
||||
x2: 100,
|
||||
y2: 200,
|
||||
r1: 10,
|
||||
r2: 50
|
||||
},
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'red' },
|
||||
{ offset: 1, color: 'green', opacity: 0 }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
function createRadialGradientSwapped() {
|
||||
return new fabric.Gradient({
|
||||
type: 'radial',
|
||||
coords: {
|
||||
x1: 0,
|
||||
y1: 10,
|
||||
x2: 100,
|
||||
y2: 200,
|
||||
r1: 50,
|
||||
r2: 10
|
||||
},
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'red' },
|
||||
{ offset: 1, color: 'green', opacity: 0 }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
var SVG_LINEAR = '<linearGradient id="SVGID_0" gradientUnits="userSpaceOnUse" x1="-50" y1="-40" x2="50" y2="150">\n<stop offset="0%" style="stop-color:red;stop-opacity: 0"/>\n<stop offset="100%" style="stop-color:green;stop-opacity: undefined"/>\n</linearGradient>\n';
|
||||
var SVG_RADIAL = '<radialGradient id="SVGID_0" gradientUnits="userSpaceOnUse" cx="50" cy="150" r="50" fx="-50" fy="-40">\n<stop offset="0%" style="stop-color:red;stop-opacity: undefined"/>\n<stop offset="100%" style="stop-color:green;stop-opacity: 0"/>\n</radialGradient>\n';
|
||||
var SVG_INTERNALRADIUS = '<radialGradient id="SVGID_0" gradientUnits="userSpaceOnUse" cx="50" cy="150" r="50" fx="-50" fy="-40">\n<stop offset="20%" style="stop-color:red;stop-opacity: undefined"/>\n<stop offset="100%" style="stop-color:green;stop-opacity: 0"/>\n</radialGradient>\n';
|
||||
var SVG_SWAPPED = '<radialGradient id="SVGID_0" gradientUnits="userSpaceOnUse" cx="-50" cy="-40" r="50" fx="50" fy="150">\n<stop offset="20%" style="stop-color:green;stop-opacity: 0"/>\n<stop offset="100%" style="stop-color:red;stop-opacity: undefined"/>\n</radialGradient>\n';
|
||||
|
||||
test('constructor linearGradient', function() {
|
||||
ok(fabric.Gradient);
|
||||
|
||||
|
|
@ -634,10 +675,35 @@
|
|||
|
||||
test('toSVG', function() {
|
||||
var gradient = createLinearGradient();
|
||||
|
||||
ok(typeof gradient.toSVG == 'function');
|
||||
});
|
||||
|
||||
// TODO: test toSVG
|
||||
test('toSVG linear', function() {
|
||||
fabric.Object.__uid = 0;
|
||||
var gradient = createLinearGradient();
|
||||
var obj = new fabric.Object({ width: 100, height: 100 });
|
||||
equal(gradient.toSVG(obj), SVG_LINEAR);
|
||||
});
|
||||
|
||||
test('toSVG radial', function() {
|
||||
fabric.Object.__uid = 0;
|
||||
var gradient = createRadialGradient();
|
||||
var obj = new fabric.Object({ width: 100, height: 100 });
|
||||
equal(gradient.toSVG(obj), SVG_RADIAL);
|
||||
});
|
||||
|
||||
test('toSVG radial with r1 > 0', function() {
|
||||
fabric.Object.__uid = 0;
|
||||
var gradient = createRadialGradientWithInternalRadius();
|
||||
var obj = new fabric.Object({ width: 100, height: 100 });
|
||||
equal(gradient.toSVG(obj), SVG_INTERNALRADIUS);
|
||||
});
|
||||
|
||||
test('toSVG radial with r1 > 0', function() {
|
||||
fabric.Object.__uid = 0;
|
||||
var gradient = createRadialGradientSwapped();
|
||||
var obj = new fabric.Object({ width: 100, height: 100 });
|
||||
equal(gradient.toSVG(obj), SVG_SWAPPED);
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
|||
Loading…
Reference in a new issue