diff --git a/CHANGELOG.md b/CHANGELOG.md
index 772a69f9119..ba0c76fc07e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog
+## [5.4.1]
+
+- fix() Fix the svg export of text with path [`#10268`](https://github.com/fabricjs/fabric.js/pull/10268)
+
## [5.4.0]
- fix() fix an issue with offScreen detection and background/overlay Vpt setting [`#8896`](https://github.com/fabricjs/fabric.js/pull/8896)
diff --git a/HEADER.js b/HEADER.js
index 6c3d9ac12c1..c78bf2a29fc 100644
--- a/HEADER.js
+++ b/HEADER.js
@@ -1,6 +1,6 @@
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
-var fabric = fabric || { version: '5.4.0' };
+var fabric = fabric || { version: '5.4.1' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
diff --git a/dist/fabric.js b/dist/fabric.js
index 2305db2d7af..8c15f855998 100644
--- a/dist/fabric.js
+++ b/dist/fabric.js
@@ -1,7 +1,7 @@
/* build: `node build.js modules=ALL exclude=gestures,accessors,erasing requirejs minifier=uglifyjs` */
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
-var fabric = fabric || { version: '5.4.0' };
+var fabric = fabric || { version: '5.4.1' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
@@ -30392,6 +30392,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
/* _TO_SVG_START_ */
(function() {
var toFixed = fabric.util.toFixed,
+ radiansToDegrees = fabric.util.radiansToDegrees,
+ calcRotateMatrix = fabric.util.calcRotateMatrix,
+ transformPoint = fabric.util.transformPoint,
multipleSpacesRegex = / +/g;
fabric.util.object.extend(fabric.Text.prototype, /** @lends fabric.Text.prototype */ {
@@ -30413,10 +30416,20 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
* @return {String} svg representation of an instance
*/
toSVG: function(reviver) {
- return this._createBaseSVGMarkup(
+ var textSvg = this._createBaseSVGMarkup(
this._toSVG(),
{ reviver: reviver, noStyle: true, withShadow: true }
);
+ if (this.path) {
+ return (
+ textSvg +
+ this._createBaseSVGMarkup(this.path._toSVG(), {
+ reviver: reviver,
+ withShadow: true,
+ })
+ );
+ }
+ return textSvg;
},
/**
@@ -30482,19 +30495,31 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
/**
* @private
*/
- _createTextCharSpan: function(_char, styleDecl, left, top) {
+ _createTextCharSpan: function(_char, styleDecl, left, top, charBox) {
var shouldUseWhitespace = _char !== _char.trim() || _char.match(multipleSpacesRegex),
styleProps = this.getSvgSpanStyles(styleDecl, shouldUseWhitespace),
fillStyles = styleProps ? 'style="' + styleProps + '"' : '',
dy = styleDecl.deltaY, dySpan = '',
- NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
+ NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
+ angleAttr = '';
if (dy) {
dySpan = ' dy="' + toFixed(dy, NUM_FRACTION_DIGITS) + '" ';
}
+ if (charBox.renderLeft !== undefined) {
+ var angle = charBox.angle;
+ angleAttr = ' rotate="' + toFixed(radiansToDegrees(angle), fabric.Object.NUM_FRACTION_DIGITS) + '" ';
+ var wBy2 = charBox.width / 2,
+ m = calcRotateMatrix({ angle: radiansToDegrees(angle) });
+ m[4] = charBox.renderLeft;
+ m[5] = charBox.renderTop;
+ var renderPoint = transformPoint({ x: -wBy2, y: 0 }, m);
+ left = renderPoint.x;
+ top = renderPoint.y;
+ }
return [
'',
+ fillStyles, angleAttr, '>',
fabric.util.string.escapeXml(_char),
''
].join('');
@@ -30514,7 +30539,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
textTopOffset += lineHeight * (1 - this._fontSizeFraction) / this.lineHeight;
for (var i = 0, len = line.length - 1; i <= len; i++) {
- timeToRender = i === len || this.charSpacing;
+ timeToRender = i === len || this.charSpacing || this.path;
charsToRender += line[i];
charBox = this.__charBounds[lineIndex][i];
if (boxWidth === 0) {
@@ -30537,7 +30562,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
}
if (timeToRender) {
style = this._getStyleDeclaration(lineIndex, i) || { };
- textSpans.push(this._createTextCharSpan(charsToRender, style, textLeftOffset, textTopOffset));
+ textSpans.push(this._createTextCharSpan(charsToRender, style, textLeftOffset, textTopOffset, charBox));
charsToRender = '';
actualStyle = nextStyle;
textLeftOffset += boxWidth;
diff --git a/dist/fabric.min.js b/dist/fabric.min.js
index a7e24e46596..e4297344ab6 100644
--- a/dist/fabric.min.js
+++ b/dist/fabric.min.js
@@ -1 +1 @@
-var jsdom,virtualWindow,fabric=fabric||{version:"5.4.0"};function resizeCanvasIfNeeded(t){var e=t.targetCanvas,i=e.width,r=e.height,n=t.destinationWidth,t=t.destinationHeight;i===n&&r===t||(e.width=n,e.height=t)}function copyGLTo2DDrawImage(t,e){var t=t.canvas,e=e.targetCanvas,i=e.getContext("2d"),r=(i.translate(0,e.height),i.scale(1,-1),t.height-e.height);i.drawImage(t,0,r,e.width,e.height,0,0,e.width,e.height)}function copyGLTo2DPutImageData(t,e){var i=e.targetCanvas.getContext("2d"),r=e.destinationWidth,e=e.destinationHeight,n=r*e*4,s=new Uint8Array(this.imageBuffer,0,n),n=new Uint8ClampedArray(this.imageBuffer,0,n),t=(t.readPixels(0,0,r,e,t.RGBA,t.UNSIGNED_BYTE,s),new ImageData(n,r,e));i.putImageData(t,0,0)}"undefined"!=typeof exports?exports.fabric=fabric:"function"==typeof define&&define.amd&&define([],function(){return fabric}),"undefined"!=typeof document&&"undefined"!=typeof window?(document instanceof("undefined"!=typeof HTMLDocument?HTMLDocument:Document)?fabric.document=document:fabric.document=document.implementation.createHTMLDocument(""),fabric.window=window):(jsdom=require("jsdom"),virtualWindow=new jsdom.JSDOM(decodeURIComponent("%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E"),{features:{FetchExternalResources:["img"]},resources:"usable"}).window,fabric.document=virtualWindow.document,fabric.jsdomImplForWrapper=require("jsdom/lib/jsdom/living/generated/utils").implForWrapper,fabric.nodeCanvas=require("jsdom/lib/jsdom/utils").Canvas,fabric.window=virtualWindow,DOMParser=fabric.window.DOMParser),fabric.isTouchSupported="ontouchstart"in fabric.window||"ontouchstart"in fabric.document||fabric.window&&fabric.window.navigator&&0t[i-2].x?1:s.x===t[i-2].x?0:-1,h=s.y>t[i-2].y?1:s.y===t[i-2].y?0:-1),n.push(["L",s.x+c*e,s.y+h*e]),n},fabric.util.getPathSegmentsInfo=l,fabric.util.getBoundsOfCurve=function(t,e,i,r,n,s,o,a){var c;if(fabric.cachesBoundsOfCurve&&(c=w.call(arguments),fabric.boundsOfCurveCache[c]))return fabric.boundsOfCurveCache[c];for(var h,l,u,f=Math.sqrt,d=Math.min,g=Math.max,p=Math.abs,m=[],v=[[],[]],b=6*t-12*i+6*n,y=-3*t+9*i-9*n+3*o,_=3*i-3*t,x=0;x<2;++x)0/g,">")},graphemeSplit:function(t){for(var e,i=0,r=[],i=0;it.x&&this.y>t.y},gte:function(t){return this.x>=t.x&&this.y>=t.y},lerp:function(t,e){return void 0===e&&(e=.5),e=Math.max(Math.min(1,e),0),new i(this.x+(t.x-this.x)*e,this.y+(t.y-this.y)*e)},distanceFrom:function(t){var e=this.x-t.x,t=this.y-t.y;return Math.sqrt(e*e+t*t)},midPointFrom:function(t){return this.lerp(t)},min:function(t){return new i(Math.min(this.x,t.x),Math.min(this.y,t.y))},max:function(t){return new i(Math.max(this.x,t.x),Math.max(this.y,t.y))},toString:function(){return this.x+","+this.y},setXY:function(t,e){return this.x=t,this.y=e,this},setX:function(t){return this.x=t,this},setY:function(t){return this.y=t,this},setFromPoint:function(t){return this.x=t.x,this.y=t.y,this},swap:function(t){var e=this.x,i=this.y;this.x=t.x,this.y=t.y,t.x=e,t.y=i},clone:function(){return new i(this.x,this.y)}}}("undefined"!=typeof exports?exports:this),function(t){var a=t.fabric||(t.fabric={});function c(t){this.status=t,this.points=[]}a.Intersection?a.warn("fabric.Intersection is already defined"):(a.Intersection=c,a.Intersection.prototype={constructor:c,appendPoint:function(t){return this.points.push(t),this},appendPoints:function(t){return this.points=this.points.concat(t),this}},a.Intersection.intersectLineLine=function(t,e,i,r){var n,s=(r.x-i.x)*(t.y-i.y)-(r.y-i.y)*(t.x-i.x),o=(e.x-t.x)*(t.y-i.y)-(e.y-t.y)*(t.x-i.x),r=(r.y-i.y)*(e.x-t.x)-(r.x-i.x)*(e.y-t.y);return 0!=r?(i=o/r,0<=(r=s/r)&&r<=1&&0<=i&&i<=1?(n=new c("Intersection")).appendPoint(new a.Point(t.x+r*(e.x-t.x),t.y+r*(e.y-t.y))):n=new c):n=new c(0==s||0==o?"Coincident":"Parallel"),n},a.Intersection.intersectLinePolygon=function(t,e,i){for(var r,n,s=new c,o=i.length,a=0;a=o&&(s.x-=o),s.x<=-o&&(s.x+=o),s.y>=o&&(s.y-=o),s.y<=o&&(s.y+=o),s.x-=t.offsetX,s.y-=t.offsetY,s}function w(t){return t.flipX!==t.flipY}function O(t,e,i,r,n){0!==t[e]&&(e=n/t._getTransformedDimensions()[r]*t[i],t.set(i,e))}function P(t,e,i,r){var n,s=e.target,o=s._getTransformedDimensions(0,s.skewY),i=T(e,e.originX,e.originY,i,r),r=Math.abs(2*i.x)-o.x,i=s.skewX,r=(r<2?n=0:(n=g(Math.atan2(r/s.scaleX,o.y/s.scaleY)),e.originX===c&&e.originY===u&&(n=-n),e.originX===l&&e.originY===h&&(n=-n),w(s)&&(n=-n)),i!==n);return r&&(o=s._getTransformedDimensions().y,s.set("skewX",n),O(s,"skewY","scaleY","y",o)),r}function k(t,e,i,r){var n,s=e.target,o=s._getTransformedDimensions(s.skewX,0),i=T(e,e.originX,e.originY,i,r),r=Math.abs(2*i.y)-o.y,i=s.skewY,r=(r<2?n=0:(n=g(Math.atan2(r/s.scaleY,o.x/s.scaleX)),e.originX===c&&e.originY===u&&(n=-n),e.originX===l&&e.originY===h&&(n=-n),w(s)&&(n=-n)),i!==n);return r&&(o=s._getTransformedDimensions().x,s.set("skewY",n),O(s,"skewX","scaleX","x",o)),r}function E(t,e,i,r,n){var s=e.target,o=s.lockScalingX,a=s.lockScalingY,n=(n=n||{}).by,t=b(t,s),c=_(s,n,t),h=e.gestureScale;if(c)return!1;if(h)l=e.scaleX*h,u=e.scaleY*h;else{if(c=T(e,e.originX,e.originY,i,r),h="y"!==n?p(c.x):1,i="x"!==n?p(c.y):1,e.signX||(e.signX=h),e.signY||(e.signY=i),s.lockScalingFlip&&(e.signX!==h||e.signY!==i))return!1;var l,u,r=s._getTransformedDimensions();u=t&&!n?(t=Math.abs(c.x)+Math.abs(c.y),f=e.original,t=t/(Math.abs(r.x*f.scaleX/s.scaleX)+Math.abs(r.y*f.scaleY/s.scaleY)),l=f.scaleX*t,f.scaleY*t):(l=Math.abs(c.x*s.scaleX/r.x),Math.abs(c.y*s.scaleY/r.y)),y(e)&&(l*=2,u*=2),e.signX!==h&&"y"!==n&&(e.originX=d[e.originX],l*=-1,e.signX=h),e.signY!==i&&"x"!==n&&(e.originY=d[e.originY],u*=-1,e.signY=i)}var f=s.scaleX,t=s.scaleY;return n?("x"===n&&s.set("scaleX",l),"y"===n&&s.set("scaleY",u)):(o||s.set("scaleX",l),a||s.set("scaleY",u)),f!==s.scaleX||t!==s.scaleY}o.scaleCursorStyleHandler=function(t,e,i){var t=b(t,i),r="";return 0!==e.x&&0===e.y?r="x":0===e.x&&0!==e.y&&(r="y"),_(i,r,t)?"not-allowed":(r=m(i,e),n[r]+"-resize")},o.skewCursorStyleHandler=function(t,e,i){var r="not-allowed";return 0!==e.x&&i.lockSkewingY||0!==e.y&&i.lockSkewingX?r:(r=m(i,e)%4,s[r]+"-resize")},o.scaleSkewCursorStyleHandler=function(t,e,i){return t[i.canvas.altActionKey]?o.skewCursorStyleHandler(t,e,i):o.scaleCursorStyleHandler(t,e,i)},o.rotationWithSnapping=S("rotating",C(function(t,e,i,r){var n,s=e.target,o=s.translateToOriginPoint(s.getCenterPoint(),e.originX,e.originY);return!s.lockRotation&&(n=Math.atan2(e.ey-o.y,e.ex-o.x),r=Math.atan2(r-o.y,i-o.x),i=g(r-n+e.theta),o=!0,0r.r2,o=(this.gradientTransform||fabric.iMatrix).concat(),a=-this.offsetX,c=-this.offsetY,h=!!e.additionalTransform,l="pixels"===this.gradientUnits?"userSpaceOnUse":"objectBoundingBox";if(n.sort(function(t,e){return t.offset-e.offset}),"objectBoundingBox"==l?(a/=t.width,c/=t.height):(a+=t.width/2,c+=t.height/2),"path"===t.type&&"percentage"!==this.gradientUnits&&(a-=t.pathOffset.x,c-=t.pathOffset.y),o[4]-=a,o[5]-=c,t='id="SVGID_'+this.id+'" gradientUnits="'+l+'"',t+=' gradientTransform="'+(h?e.additionalTransform+" ":"")+fabric.util.matrixToSVG(o)+'" ',"linear"===this.type?i=["\n']:"radial"===this.type&&(i=["\n']),"radial"===this.type){if(s)for((n=n.concat()).reverse(),f=0,d=n.length;f\n')}return i.push("linear"===this.type?"\n":"\n"),i.join("")},toLive:function(t){var e,i,r,n=fabric.util.object.clone(this.coords);if(this.type){for("linear"===this.type?e=t.createLinearGradient(n.x1,n.y1,n.x2,n.y2):"radial"===this.type&&(e=t.createRadialGradient(n.x1,n.y1,n.r1,n.x2,n.y2,n.r2)),i=0,r=this.colorStops.length;i\n\n\n'},setOptions:function(t){for(var e in t)this[e]=t[e]},toLive:function(t){var e=this.source;if(!e)return"";if(void 0!==e.src){if(!e.complete)return"";if(0===e.naturalWidth||0===e.naturalHeight)return""}return t.createPattern(e,this.repeat)}})}(),function(t){var o=t.fabric||(t.fabric={}),a=o.util.toFixed;o.Shadow?o.warn("fabric.Shadow is already defined."):(o.Shadow=o.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,nonScaling:!1,initialize:function(t){for(var e in t="string"==typeof t?this._parseShadow(t):t)this[e]=t[e];this.id=o.Object.__uid++},_parseShadow:function(t){var t=t.trim(),e=o.Shadow.reOffsetsAndBlur.exec(t)||[];return{color:(t.replace(o.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(),offsetX:parseFloat(e[1],10)||0,offsetY:parseFloat(e[2],10)||0,blur:parseFloat(e[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(t){var e=40,i=40,r=o.Object.NUM_FRACTION_DIGITS,n=o.util.rotateVector({x:this.offsetX,y:this.offsetY},o.util.degreesToRadians(-t.angle)),s=new o.Color(this.color);return t.width&&t.height&&(e=100*a((Math.abs(n.x)+this.blur)/t.width,r)+20,i=100*a((Math.abs(n.y)+this.blur)/t.height,r)+20),t.flipX&&(n.x*=-1),t.flipY&&(n.y*=-1),'\n\t\n\t\n\t\n\t\n\t\n\t\t\n\t\t\n\t\n\n'},toObject:function(){var e,i;return this.includeDefaultValues?{color:this.color,blur:this.blur,offsetX:this.offsetX,offsetY:this.offsetY,affectStroke:this.affectStroke,nonScaling:this.nonScaling}:(e={},i=o.Shadow.prototype,["color","blur","offsetX","offsetY","affectStroke","nonScaling"].forEach(function(t){this[t]!==i[t]&&(e[t]=this[t])},this),e)}}),o.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(\d+(?:\.\d*)?(?:px)?)?(?:\s?|$)(?:$|\s)/)}("undefined"!=typeof exports?exports:this),function(){var n,t,h,a,s,o,i,r,e;fabric.StaticCanvas?fabric.warn("fabric.StaticCanvas is already defined."):(n=fabric.util.object.extend,t=fabric.util.getElementOffset,h=fabric.util.removeFromArray,a=fabric.util.toFixed,s=fabric.util.transformPoint,o=fabric.util.invertTransform,i=fabric.util.getNodeCanvas,r=fabric.util.createCanvasElement,e=new Error("Could not initialize `canvas` element"),fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(t,e){e=e||{},this.renderAndResetBound=this.renderAndReset.bind(this),this.requestRenderAllBound=this.requestRenderAll.bind(this),this._initStatic(t,e)},backgroundColor:"",backgroundImage:null,overlayColor:"",overlayImage:null,includeDefaultValues:!0,stateful:!1,renderOnAddRemove:!0,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,viewportTransform:fabric.iMatrix.concat(),backgroundVpt:!0,overlayVpt:!0,enableRetinaScaling:!0,vptCoords:{},skipOffscreen:!0,clipPath:void 0,_initStatic:function(t,e){var i=this.requestRenderAllBound;this._objects=[],this._createLowerCanvas(t),this._initOptions(e),this.interactive||this._initRetinaScaling(),e.overlayImage&&this.setOverlayImage(e.overlayImage,i),e.backgroundImage&&this.setBackgroundImage(e.backgroundImage,i),e.backgroundColor&&this.setBackgroundColor(e.backgroundColor,i),e.overlayColor&&this.setOverlayColor(e.overlayColor,i),this.calcOffset()},_isRetinaScaling:function(){return 1\n'),this._setSVGBgOverlayColor(i,"background"),this._setSVGBgOverlayImage(i,"backgroundImage",e),this._setSVGObjects(i,e),this.clipPath&&i.push("\n"),this._setSVGBgOverlayColor(i,"overlay"),this._setSVGBgOverlayImage(i,"overlayImage",e),i.push(""),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,r=e.width||this.width,n=e.height||this.height,s='viewBox="0 0 '+this.width+" "+this.height+'" ',o=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?s='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,s='viewBox="'+a(-i[4]/i[0],o)+" "+a(-i[5]/i[3],o)+" "+a(this.width/i[0],o)+" "+a(this.height/i[3],o)+'" '),t.push(""),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,r=e.width||this.width,n=e.height||this.height,s='viewBox="0 0 '+this.width+" "+this.height+'" ',o=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?s='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,s='viewBox="'+a(-i[4]/i[0],o)+" "+a(-i[5]/i[3],o)+" "+a(this.width/i[0],o)+" "+a(this.height/i[3],o)+'" '),t.push("