@nasser-sw/fabric 7.0.1-beta17 → 7.0.1-beta19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/.history/package_20251226051014.json +164 -0
  2. package/.history/package_20251226164045.json +164 -0
  3. package/dist/fabric.d.ts +2 -0
  4. package/dist/fabric.d.ts.map +1 -1
  5. package/dist/fabric.min.mjs +1 -1
  6. package/dist/fabric.mjs +2 -0
  7. package/dist/fabric.mjs.map +1 -1
  8. package/dist/index.js +1760 -368
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.min.js +1 -1
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/index.min.mjs +1 -1
  13. package/dist/index.min.mjs.map +1 -1
  14. package/dist/index.mjs +1759 -369
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.node.cjs +1760 -368
  17. package/dist/index.node.cjs.map +1 -1
  18. package/dist/index.node.mjs +1759 -369
  19. package/dist/index.node.mjs.map +1 -1
  20. package/dist/package.json.min.mjs +1 -1
  21. package/dist/package.json.mjs +1 -1
  22. package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts +31 -0
  23. package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts.map +1 -0
  24. package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.min.mjs +2 -0
  25. package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.min.mjs.map +1 -0
  26. package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.mjs +81 -0
  27. package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.mjs.map +1 -0
  28. package/dist/src/LayoutManager/index.d.ts +1 -0
  29. package/dist/src/LayoutManager/index.d.ts.map +1 -1
  30. package/dist/src/controls/Control.d.ts.map +1 -1
  31. package/dist/src/controls/Control.min.mjs +1 -1
  32. package/dist/src/controls/Control.min.mjs.map +1 -1
  33. package/dist/src/controls/Control.mjs +19 -1
  34. package/dist/src/controls/Control.mjs.map +1 -1
  35. package/dist/src/controls/commonControls.d.ts.map +1 -1
  36. package/dist/src/controls/commonControls.min.mjs +1 -1
  37. package/dist/src/controls/commonControls.min.mjs.map +1 -1
  38. package/dist/src/controls/commonControls.mjs +25 -6
  39. package/dist/src/controls/commonControls.mjs.map +1 -1
  40. package/dist/src/controls/controlRendering.d.ts +20 -0
  41. package/dist/src/controls/controlRendering.d.ts.map +1 -1
  42. package/dist/src/controls/controlRendering.min.mjs +1 -1
  43. package/dist/src/controls/controlRendering.min.mjs.map +1 -1
  44. package/dist/src/controls/controlRendering.mjs +63 -1
  45. package/dist/src/controls/controlRendering.mjs.map +1 -1
  46. package/dist/src/shapes/Frame.d.ts +298 -0
  47. package/dist/src/shapes/Frame.d.ts.map +1 -0
  48. package/dist/src/shapes/Frame.min.mjs +2 -0
  49. package/dist/src/shapes/Frame.min.mjs.map +1 -0
  50. package/dist/src/shapes/Frame.mjs +1236 -0
  51. package/dist/src/shapes/Frame.mjs.map +1 -0
  52. package/dist/src/shapes/Object/defaultValues.d.ts.map +1 -1
  53. package/dist/src/shapes/Object/defaultValues.min.mjs +1 -1
  54. package/dist/src/shapes/Object/defaultValues.min.mjs.map +1 -1
  55. package/dist/src/shapes/Object/defaultValues.mjs +8 -7
  56. package/dist/src/shapes/Object/defaultValues.mjs.map +1 -1
  57. package/dist-extensions/fabric.d.ts +2 -0
  58. package/dist-extensions/fabric.d.ts.map +1 -1
  59. package/dist-extensions/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts +31 -0
  60. package/dist-extensions/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts.map +1 -0
  61. package/dist-extensions/src/LayoutManager/index.d.ts +1 -0
  62. package/dist-extensions/src/LayoutManager/index.d.ts.map +1 -1
  63. package/dist-extensions/src/controls/Control.d.ts.map +1 -1
  64. package/dist-extensions/src/controls/commonControls.d.ts.map +1 -1
  65. package/dist-extensions/src/controls/controlRendering.d.ts +20 -0
  66. package/dist-extensions/src/controls/controlRendering.d.ts.map +1 -1
  67. package/dist-extensions/src/shapes/Frame.d.ts +298 -0
  68. package/dist-extensions/src/shapes/Frame.d.ts.map +1 -0
  69. package/dist-extensions/src/shapes/Object/defaultValues.d.ts.map +1 -1
  70. package/fabric.ts +8 -0
  71. package/package.json +1 -1
  72. package/src/LayoutManager/LayoutStrategies/FrameLayout.ts +80 -0
  73. package/src/LayoutManager/index.ts +1 -0
  74. package/src/controls/Control.ts +40 -1
  75. package/src/controls/commonControls.ts +22 -0
  76. package/src/controls/controlRendering.ts +83 -0
  77. package/src/shapes/Frame.ts +1361 -0
  78. package/src/shapes/Object/defaultValues.ts +8 -7
@@ -26,4 +26,24 @@ export declare function renderCircleControl(this: Control, ctx: CanvasRenderingC
26
26
  * @param {FabricObject} fabricObject the fabric object for which we are rendering controls
27
27
  */
28
28
  export declare function renderSquareControl(this: Control, ctx: CanvasRenderingContext2D, left: number, top: number, styleOverride: ControlRenderingStyleOverride, fabricObject: InteractiveFabricObject): void;
29
+ /**
30
+ * Render a horizontal pill control (for left/right side handles).
31
+ * Modern Canva-style appearance.
32
+ * @param {CanvasRenderingContext2D} ctx context to render on
33
+ * @param {Number} left x coordinate where the control center should be
34
+ * @param {Number} top y coordinate where the control center should be
35
+ * @param {Object} styleOverride override for FabricObject controls style
36
+ * @param {FabricObject} fabricObject the fabric object for which we are rendering controls
37
+ */
38
+ export declare function renderHorizontalPillControl(this: Control, ctx: CanvasRenderingContext2D, left: number, top: number, styleOverride: ControlRenderingStyleOverride, fabricObject: InteractiveFabricObject): void;
39
+ /**
40
+ * Render a vertical pill control (for top/bottom side handles).
41
+ * Modern Canva-style appearance.
42
+ * @param {CanvasRenderingContext2D} ctx context to render on
43
+ * @param {Number} left x coordinate where the control center should be
44
+ * @param {Number} top y coordinate where the control center should be
45
+ * @param {Object} styleOverride override for FabricObject controls style
46
+ * @param {FabricObject} fabricObject the fabric object for which we are rendering controls
47
+ */
48
+ export declare function renderVerticalPillControl(this: Control, ctx: CanvasRenderingContext2D, left: number, top: number, styleOverride: ControlRenderingStyleOverride, fabricObject: InteractiveFabricObject): void;
29
49
  //# sourceMappingURL=controlRendering.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"controlRendering.d.ts","sourceRoot":"","sources":["../../../src/controls/controlRendering.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAElF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,MAAM,6BAA6B,GAAG,OAAO,CACjD,IAAI,CACF,uBAAuB,EACrB,aAAa,GACb,YAAY,GACZ,aAAa,GACb,mBAAmB,GACnB,iBAAiB,GACjB,oBAAoB,CACvB,CACF,CAAC;AAEF,MAAM,MAAM,eAAe,CACzB,CAAC,SAAS,uBAAuB,GAAG,uBAAuB,IACzD,CACF,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,CAAC,KACZ,IAAI,CAAC;AAEV;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,uBAAuB,QAwCtC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,uBAAuB,QAgCtC"}
1
+ {"version":3,"file":"controlRendering.d.ts","sourceRoot":"","sources":["../../../src/controls/controlRendering.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAElF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASzC,MAAM,MAAM,6BAA6B,GAAG,OAAO,CACjD,IAAI,CACF,uBAAuB,EACrB,aAAa,GACb,YAAY,GACZ,aAAa,GACb,mBAAmB,GACnB,iBAAiB,GACjB,oBAAoB,CACvB,CACF,CAAC;AAEF,MAAM,MAAM,eAAe,CACzB,CAAC,SAAS,uBAAuB,GAAG,uBAAuB,IACzD,CACF,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,CAAC,KACZ,IAAI,CAAC;AAEV;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,uBAAuB,QAwCtC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,uBAAuB,QAgCtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,uBAAuB,QAqBtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,6BAA6B,EAC5C,YAAY,EAAE,uBAAuB,QAqBtC"}
@@ -1,2 +1,2 @@
1
- import{STROKE as r,FILL as e,twoMathPi as o}from"../constants.min.mjs";import{degreesToRadians as n}from"../util/misc/radiansDegreesConversion.min.mjs";function t(n,t,s,c,i){c=c||{};const l=this.sizeX||c.cornerSize||i.cornerSize,a=this.sizeY||c.cornerSize||i.cornerSize,S=void 0!==c.transparentCorners?c.transparentCorners:i.transparentCorners,C=S?r:e,k=!S&&(c.cornerStrokeColor||i.cornerStrokeColor);let z,m=t,p=s;n.save(),n.fillStyle=c.cornerColor||i.cornerColor||"",n.strokeStyle=c.cornerStrokeColor||i.cornerStrokeColor||"",l>a?(z=l,n.scale(1,a/l),p=s*l/a):a>l?(z=a,n.scale(l/a,1),m=t*a/l):z=l,n.beginPath(),n.arc(m,p,z/2,0,o,!1),n[C](),k&&n.stroke(),n.restore()}function s(o,t,s,c,i){c=c||{};const l=this.sizeX||c.cornerSize||i.cornerSize,a=this.sizeY||c.cornerSize||i.cornerSize,S=void 0!==c.transparentCorners?c.transparentCorners:i.transparentCorners,C=S?r:e,k=!S&&(c.cornerStrokeColor||i.cornerStrokeColor),z=l/2,m=a/2;o.save(),o.fillStyle=c.cornerColor||i.cornerColor||"",o.strokeStyle=c.cornerStrokeColor||i.cornerStrokeColor||"",o.translate(t,s);const p=i.getTotalAngle();o.rotate(n(p)),o[`${C}Rect`](-z,-m,l,a),k&&o.strokeRect(-z,-m,l,a),o.restore()}export{t as renderCircleControl,s as renderSquareControl};
1
+ import{STROKE as r,FILL as o,twoMathPi as e}from"../constants.min.mjs";import{degreesToRadians as t}from"../util/misc/radiansDegreesConversion.min.mjs";function n(t,n,l,s,c){s=s||{};const i=this.sizeX||s.cornerSize||c.cornerSize,a=this.sizeY||s.cornerSize||c.cornerSize,f=void 0!==s.transparentCorners?s.transparentCorners:c.transparentCorners,S=f?r:o,C=!f&&(s.cornerStrokeColor||c.cornerStrokeColor);let k,z=n,g=l;t.save(),t.fillStyle=s.cornerColor||c.cornerColor||"",t.strokeStyle=s.cornerStrokeColor||c.cornerStrokeColor||"",i>a?(k=i,t.scale(1,a/i),g=l*i/a):a>i?(k=a,t.scale(i/a,1),z=n*a/i):k=i,t.beginPath(),t.arc(z,g,k/2,0,e,!1),t[S](),C&&t.stroke(),t.restore()}function l(e,n,l,s,c){s=s||{};const i=this.sizeX||s.cornerSize||c.cornerSize,a=this.sizeY||s.cornerSize||c.cornerSize,f=void 0!==s.transparentCorners?s.transparentCorners:c.transparentCorners,S=f?r:o,C=!f&&(s.cornerStrokeColor||c.cornerStrokeColor),k=i/2,z=a/2;e.save(),e.fillStyle=s.cornerColor||c.cornerColor||"",e.strokeStyle=s.cornerStrokeColor||c.cornerStrokeColor||"",e.translate(n,l);const g=c.getTotalAngle();e.rotate(t(g)),e[`${S}Rect`](-k,-z,i,a),C&&e.strokeRect(-k,-z,i,a),e.restore()}function s(r,o,e,n,l){n=n||{};r.save(),r.translate(o,e);const s=l.getTotalAngle();r.rotate(t(s)),r.fillStyle=n.cornerColor||l.cornerColor||"#ffffff",r.strokeStyle=n.cornerStrokeColor||l.cornerStrokeColor||"#0d99ff",r.lineWidth=1.5,r.beginPath(),r.roundRect(-3,-10,6,20,3),r.fill(),r.stroke(),r.restore()}function c(r,o,e,n,l){n=n||{};r.save(),r.translate(o,e);const s=l.getTotalAngle();r.rotate(t(s)),r.fillStyle=n.cornerColor||l.cornerColor||"#ffffff",r.strokeStyle=n.cornerStrokeColor||l.cornerStrokeColor||"#0d99ff",r.lineWidth=1.5,r.beginPath(),r.roundRect(-10,-3,20,6,3),r.fill(),r.stroke(),r.restore()}export{n as renderCircleControl,s as renderHorizontalPillControl,l as renderSquareControl,c as renderVerticalPillControl};
2
2
  //# sourceMappingURL=controlRendering.min.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"controlRendering.min.mjs","sources":["../../../src/controls/controlRendering.ts"],"sourcesContent":["import { FILL, STROKE, twoMathPi } from '../constants';\r\nimport type { InteractiveFabricObject } from '../shapes/Object/InteractiveObject';\r\nimport { degreesToRadians } from '../util/misc/radiansDegreesConversion';\r\nimport type { Control } from './Control';\r\n\r\nexport type ControlRenderingStyleOverride = Partial<\r\n Pick<\r\n InteractiveFabricObject,\r\n | 'cornerStyle'\r\n | 'cornerSize'\r\n | 'cornerColor'\r\n | 'cornerStrokeColor'\r\n | 'cornerDashArray'\r\n | 'transparentCorners'\r\n >\r\n>;\r\n\r\nexport type ControlRenderer<\r\n O extends InteractiveFabricObject = InteractiveFabricObject,\r\n> = (\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: O,\r\n) => void;\r\n\r\n/**\r\n * Render a round control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderCircleControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor);\r\n let myLeft = left,\r\n myTop = top,\r\n size;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n // TODO: use proper ellipse code.\r\n if (xSize > ySize) {\r\n size = xSize;\r\n ctx.scale(1.0, ySize / xSize);\r\n myTop = (top * xSize) / ySize;\r\n } else if (ySize > xSize) {\r\n size = ySize;\r\n ctx.scale(xSize / ySize, 1.0);\r\n myLeft = (left * ySize) / xSize;\r\n } else {\r\n size = xSize;\r\n }\r\n ctx.beginPath();\r\n ctx.arc(myLeft, myTop, size / 2, 0, twoMathPi, false);\r\n ctx[methodName]();\r\n if (stroke) {\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a square control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderSquareControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor),\r\n xSizeBy2 = xSize / 2,\r\n ySizeBy2 = ySize / 2;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n ctx.translate(left, top);\r\n // angle is relative to canvas plane\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n // this does not work, and fixed with ( && ) does not make sense.\r\n // to have real transparent corners we need the controls on upperCanvas\r\n // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n ctx[`${methodName}Rect`](-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n if (stroke) {\r\n ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n }\r\n ctx.restore();\r\n}\r\n"],"names":["renderCircleControl","ctx","left","top","styleOverride","fabricObject","xSize","this","sizeX","cornerSize","ySize","sizeY","transparentCorners","methodName","STROKE","FILL","stroke","cornerStrokeColor","size","myLeft","myTop","save","fillStyle","cornerColor","strokeStyle","scale","beginPath","arc","twoMathPi","restore","renderSquareControl","xSizeBy2","ySizeBy2","translate","angle","getTotalAngle","rotate","degreesToRadians","strokeRect"],"mappings":"wJAsCO,SAASA,EAEdC,EACAC,EACAC,EACAC,EACAC,GAEAD,EAAgBA,GAAiB,CAAA,EACjC,MAAME,EACFC,KAAKC,OAASJ,EAAcK,YAAcJ,EAAaI,WACzDC,EAAQH,KAAKI,OAASP,EAAcK,YAAcJ,EAAaI,WAC/DG,OAC8C,IAArCR,EAAcQ,mBACjBR,EAAcQ,mBACdP,EAAaO,mBACnBC,EAAaD,EAAqBE,EAASC,EAC3CC,GACGJ,IACAR,EAAca,mBAAqBZ,EAAaY,mBACrD,IAEEC,EAFEC,EAASjB,EACXkB,EAAQjB,EAEVF,EAAIoB,OACJpB,EAAIqB,UAAYlB,EAAcmB,aAAelB,EAAakB,aAAe,GACzEtB,EAAIuB,YACFpB,EAAca,mBAAqBZ,EAAaY,mBAAqB,GAEnEX,EAAQI,GACVQ,EAAOZ,EACPL,EAAIwB,MAAM,EAAKf,EAAQJ,GACvBc,EAASjB,EAAMG,EAASI,GACfA,EAAQJ,GACjBY,EAAOR,EACPT,EAAIwB,MAAMnB,EAAQI,EAAO,GACzBS,EAAUjB,EAAOQ,EAASJ,GAE1BY,EAAOZ,EAETL,EAAIyB,YACJzB,EAAI0B,IAAIR,EAAQC,EAAOF,EAAO,EAAG,EAAGU,GAAW,GAC/C3B,EAAIY,KACAG,GACFf,EAAIe,SAENf,EAAI4B,SACN,CAaO,SAASC,EAEd7B,EACAC,EACAC,EACAC,EACAC,GAEAD,EAAgBA,GAAiB,CAAA,EACjC,MAAME,EACFC,KAAKC,OAASJ,EAAcK,YAAcJ,EAAaI,WACzDC,EAAQH,KAAKI,OAASP,EAAcK,YAAcJ,EAAaI,WAC/DG,OAC8C,IAArCR,EAAcQ,mBACjBR,EAAcQ,mBACdP,EAAaO,mBACnBC,EAAaD,EAAqBE,EAASC,EAC3CC,GACGJ,IACAR,EAAca,mBAAqBZ,EAAaY,mBACnDc,EAAWzB,EAAQ,EACnB0B,EAAWtB,EAAQ,EACrBT,EAAIoB,OACJpB,EAAIqB,UAAYlB,EAAcmB,aAAelB,EAAakB,aAAe,GACzEtB,EAAIuB,YACFpB,EAAca,mBAAqBZ,EAAaY,mBAAqB,GACvEhB,EAAIgC,UAAU/B,EAAMC,GAEpB,MAAM+B,EAAQ7B,EAAa8B,gBAC3BlC,EAAImC,OAAOC,EAAiBH,IAI5BjC,EAAI,GAAGY,UAAmBkB,GAAWC,EAAU1B,EAAOI,GAClDM,GACFf,EAAIqC,YAAYP,GAAWC,EAAU1B,EAAOI,GAE9CT,EAAI4B,SACN"}
1
+ {"version":3,"file":"controlRendering.min.mjs","sources":["../../../src/controls/controlRendering.ts"],"sourcesContent":["import { FILL, STROKE, twoMathPi } from '../constants';\r\nimport type { InteractiveFabricObject } from '../shapes/Object/InteractiveObject';\r\nimport { degreesToRadians } from '../util/misc/radiansDegreesConversion';\r\nimport type { Control } from './Control';\r\n\r\n/**\r\n * Pill dimensions for side controls (Canva-style)\r\n */\r\nconst PILL_WIDTH = 6;\r\nconst PILL_HEIGHT = 20;\r\nconst PILL_RADIUS = 3;\r\n\r\nexport type ControlRenderingStyleOverride = Partial<\r\n Pick<\r\n InteractiveFabricObject,\r\n | 'cornerStyle'\r\n | 'cornerSize'\r\n | 'cornerColor'\r\n | 'cornerStrokeColor'\r\n | 'cornerDashArray'\r\n | 'transparentCorners'\r\n >\r\n>;\r\n\r\nexport type ControlRenderer<\r\n O extends InteractiveFabricObject = InteractiveFabricObject,\r\n> = (\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: O,\r\n) => void;\r\n\r\n/**\r\n * Render a round control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderCircleControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor);\r\n let myLeft = left,\r\n myTop = top,\r\n size;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n // TODO: use proper ellipse code.\r\n if (xSize > ySize) {\r\n size = xSize;\r\n ctx.scale(1.0, ySize / xSize);\r\n myTop = (top * xSize) / ySize;\r\n } else if (ySize > xSize) {\r\n size = ySize;\r\n ctx.scale(xSize / ySize, 1.0);\r\n myLeft = (left * ySize) / xSize;\r\n } else {\r\n size = xSize;\r\n }\r\n ctx.beginPath();\r\n ctx.arc(myLeft, myTop, size / 2, 0, twoMathPi, false);\r\n ctx[methodName]();\r\n if (stroke) {\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a square control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderSquareControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor),\r\n xSizeBy2 = xSize / 2,\r\n ySizeBy2 = ySize / 2;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n ctx.translate(left, top);\r\n // angle is relative to canvas plane\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n // this does not work, and fixed with ( && ) does not make sense.\r\n // to have real transparent corners we need the controls on upperCanvas\r\n // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n ctx[`${methodName}Rect`](-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n if (stroke) {\r\n ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n }\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a horizontal pill control (for left/right side handles).\r\n * Modern Canva-style appearance.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderHorizontalPillControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const width = PILL_WIDTH;\r\n const height = PILL_HEIGHT;\r\n const radius = PILL_RADIUS;\r\n\r\n ctx.save();\r\n ctx.translate(left, top);\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';\r\n ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';\r\n ctx.lineWidth = 1.5;\r\n\r\n ctx.beginPath();\r\n ctx.roundRect(-width / 2, -height / 2, width, height, radius);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a vertical pill control (for top/bottom side handles).\r\n * Modern Canva-style appearance.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderVerticalPillControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const width = PILL_HEIGHT; // Swapped for vertical\r\n const height = PILL_WIDTH;\r\n const radius = PILL_RADIUS;\r\n\r\n ctx.save();\r\n ctx.translate(left, top);\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';\r\n ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';\r\n ctx.lineWidth = 1.5;\r\n\r\n ctx.beginPath();\r\n ctx.roundRect(-width / 2, -height / 2, width, height, radius);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n"],"names":["renderCircleControl","ctx","left","top","styleOverride","fabricObject","xSize","this","sizeX","cornerSize","ySize","sizeY","transparentCorners","methodName","STROKE","FILL","stroke","cornerStrokeColor","size","myLeft","myTop","save","fillStyle","cornerColor","strokeStyle","scale","beginPath","arc","twoMathPi","restore","renderSquareControl","xSizeBy2","ySizeBy2","translate","angle","getTotalAngle","rotate","degreesToRadians","strokeRect","renderHorizontalPillControl","lineWidth","roundRect","fill","renderVerticalPillControl"],"mappings":"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"}
@@ -1,6 +1,12 @@
1
1
  import { STROKE, FILL, twoMathPi } from '../constants.mjs';
2
2
  import { degreesToRadians } from '../util/misc/radiansDegreesConversion.mjs';
3
3
 
4
+ /**
5
+ * Pill dimensions for side controls (Canva-style)
6
+ */
7
+ const PILL_WIDTH = 6;
8
+ const PILL_HEIGHT = 20;
9
+ const PILL_RADIUS = 3;
4
10
  /**
5
11
  * Render a round control, as per fabric features.
6
12
  * This function is written to respect object properties like transparentCorners, cornerSize
@@ -83,5 +89,61 @@ function renderSquareControl(ctx, left, top, styleOverride, fabricObject) {
83
89
  ctx.restore();
84
90
  }
85
91
 
86
- export { renderCircleControl, renderSquareControl };
92
+ /**
93
+ * Render a horizontal pill control (for left/right side handles).
94
+ * Modern Canva-style appearance.
95
+ * @param {CanvasRenderingContext2D} ctx context to render on
96
+ * @param {Number} left x coordinate where the control center should be
97
+ * @param {Number} top y coordinate where the control center should be
98
+ * @param {Object} styleOverride override for FabricObject controls style
99
+ * @param {FabricObject} fabricObject the fabric object for which we are rendering controls
100
+ */
101
+ function renderHorizontalPillControl(ctx, left, top, styleOverride, fabricObject) {
102
+ styleOverride = styleOverride || {};
103
+ const width = PILL_WIDTH;
104
+ const height = PILL_HEIGHT;
105
+ const radius = PILL_RADIUS;
106
+ ctx.save();
107
+ ctx.translate(left, top);
108
+ const angle = fabricObject.getTotalAngle();
109
+ ctx.rotate(degreesToRadians(angle));
110
+ ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';
111
+ ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';
112
+ ctx.lineWidth = 1.5;
113
+ ctx.beginPath();
114
+ ctx.roundRect(-width / 2, -height / 2, width, height, radius);
115
+ ctx.fill();
116
+ ctx.stroke();
117
+ ctx.restore();
118
+ }
119
+
120
+ /**
121
+ * Render a vertical pill control (for top/bottom side handles).
122
+ * Modern Canva-style appearance.
123
+ * @param {CanvasRenderingContext2D} ctx context to render on
124
+ * @param {Number} left x coordinate where the control center should be
125
+ * @param {Number} top y coordinate where the control center should be
126
+ * @param {Object} styleOverride override for FabricObject controls style
127
+ * @param {FabricObject} fabricObject the fabric object for which we are rendering controls
128
+ */
129
+ function renderVerticalPillControl(ctx, left, top, styleOverride, fabricObject) {
130
+ styleOverride = styleOverride || {};
131
+ const width = PILL_HEIGHT; // Swapped for vertical
132
+ const height = PILL_WIDTH;
133
+ const radius = PILL_RADIUS;
134
+ ctx.save();
135
+ ctx.translate(left, top);
136
+ const angle = fabricObject.getTotalAngle();
137
+ ctx.rotate(degreesToRadians(angle));
138
+ ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';
139
+ ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';
140
+ ctx.lineWidth = 1.5;
141
+ ctx.beginPath();
142
+ ctx.roundRect(-width / 2, -height / 2, width, height, radius);
143
+ ctx.fill();
144
+ ctx.stroke();
145
+ ctx.restore();
146
+ }
147
+
148
+ export { renderCircleControl, renderHorizontalPillControl, renderSquareControl, renderVerticalPillControl };
87
149
  //# sourceMappingURL=controlRendering.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"controlRendering.mjs","sources":["../../../src/controls/controlRendering.ts"],"sourcesContent":["import { FILL, STROKE, twoMathPi } from '../constants';\r\nimport type { InteractiveFabricObject } from '../shapes/Object/InteractiveObject';\r\nimport { degreesToRadians } from '../util/misc/radiansDegreesConversion';\r\nimport type { Control } from './Control';\r\n\r\nexport type ControlRenderingStyleOverride = Partial<\r\n Pick<\r\n InteractiveFabricObject,\r\n | 'cornerStyle'\r\n | 'cornerSize'\r\n | 'cornerColor'\r\n | 'cornerStrokeColor'\r\n | 'cornerDashArray'\r\n | 'transparentCorners'\r\n >\r\n>;\r\n\r\nexport type ControlRenderer<\r\n O extends InteractiveFabricObject = InteractiveFabricObject,\r\n> = (\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: O,\r\n) => void;\r\n\r\n/**\r\n * Render a round control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderCircleControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor);\r\n let myLeft = left,\r\n myTop = top,\r\n size;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n // TODO: use proper ellipse code.\r\n if (xSize > ySize) {\r\n size = xSize;\r\n ctx.scale(1.0, ySize / xSize);\r\n myTop = (top * xSize) / ySize;\r\n } else if (ySize > xSize) {\r\n size = ySize;\r\n ctx.scale(xSize / ySize, 1.0);\r\n myLeft = (left * ySize) / xSize;\r\n } else {\r\n size = xSize;\r\n }\r\n ctx.beginPath();\r\n ctx.arc(myLeft, myTop, size / 2, 0, twoMathPi, false);\r\n ctx[methodName]();\r\n if (stroke) {\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a square control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderSquareControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor),\r\n xSizeBy2 = xSize / 2,\r\n ySizeBy2 = ySize / 2;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n ctx.translate(left, top);\r\n // angle is relative to canvas plane\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n // this does not work, and fixed with ( && ) does not make sense.\r\n // to have real transparent corners we need the controls on upperCanvas\r\n // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n ctx[`${methodName}Rect`](-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n if (stroke) {\r\n ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n }\r\n ctx.restore();\r\n}\r\n"],"names":["renderCircleControl","ctx","left","top","styleOverride","fabricObject","xSize","sizeX","cornerSize","ySize","sizeY","transparentCorners","methodName","STROKE","FILL","stroke","cornerStrokeColor","myLeft","myTop","size","save","fillStyle","cornerColor","strokeStyle","scale","beginPath","arc","twoMathPi","restore","renderSquareControl","xSizeBy2","ySizeBy2","translate","angle","getTotalAngle","rotate","degreesToRadians","strokeRect"],"mappings":"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"}
1
+ {"version":3,"file":"controlRendering.mjs","sources":["../../../src/controls/controlRendering.ts"],"sourcesContent":["import { FILL, STROKE, twoMathPi } from '../constants';\r\nimport type { InteractiveFabricObject } from '../shapes/Object/InteractiveObject';\r\nimport { degreesToRadians } from '../util/misc/radiansDegreesConversion';\r\nimport type { Control } from './Control';\r\n\r\n/**\r\n * Pill dimensions for side controls (Canva-style)\r\n */\r\nconst PILL_WIDTH = 6;\r\nconst PILL_HEIGHT = 20;\r\nconst PILL_RADIUS = 3;\r\n\r\nexport type ControlRenderingStyleOverride = Partial<\r\n Pick<\r\n InteractiveFabricObject,\r\n | 'cornerStyle'\r\n | 'cornerSize'\r\n | 'cornerColor'\r\n | 'cornerStrokeColor'\r\n | 'cornerDashArray'\r\n | 'transparentCorners'\r\n >\r\n>;\r\n\r\nexport type ControlRenderer<\r\n O extends InteractiveFabricObject = InteractiveFabricObject,\r\n> = (\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: O,\r\n) => void;\r\n\r\n/**\r\n * Render a round control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderCircleControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor);\r\n let myLeft = left,\r\n myTop = top,\r\n size;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n // TODO: use proper ellipse code.\r\n if (xSize > ySize) {\r\n size = xSize;\r\n ctx.scale(1.0, ySize / xSize);\r\n myTop = (top * xSize) / ySize;\r\n } else if (ySize > xSize) {\r\n size = ySize;\r\n ctx.scale(xSize / ySize, 1.0);\r\n myLeft = (left * ySize) / xSize;\r\n } else {\r\n size = xSize;\r\n }\r\n ctx.beginPath();\r\n ctx.arc(myLeft, myTop, size / 2, 0, twoMathPi, false);\r\n ctx[methodName]();\r\n if (stroke) {\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a square control, as per fabric features.\r\n * This function is written to respect object properties like transparentCorners, cornerSize\r\n * cornerColor, cornerStrokeColor\r\n * plus the addition of offsetY and offsetX.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderSquareControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const xSize =\r\n this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\r\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\r\n transparentCorners =\r\n typeof styleOverride.transparentCorners !== 'undefined'\r\n ? styleOverride.transparentCorners\r\n : fabricObject.transparentCorners,\r\n methodName = transparentCorners ? STROKE : FILL,\r\n stroke =\r\n !transparentCorners &&\r\n (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor),\r\n xSizeBy2 = xSize / 2,\r\n ySizeBy2 = ySize / 2;\r\n ctx.save();\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '';\r\n ctx.strokeStyle =\r\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '';\r\n ctx.translate(left, top);\r\n // angle is relative to canvas plane\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n // this does not work, and fixed with ( && ) does not make sense.\r\n // to have real transparent corners we need the controls on upperCanvas\r\n // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n ctx[`${methodName}Rect`](-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n if (stroke) {\r\n ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\r\n }\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a horizontal pill control (for left/right side handles).\r\n * Modern Canva-style appearance.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderHorizontalPillControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const width = PILL_WIDTH;\r\n const height = PILL_HEIGHT;\r\n const radius = PILL_RADIUS;\r\n\r\n ctx.save();\r\n ctx.translate(left, top);\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';\r\n ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';\r\n ctx.lineWidth = 1.5;\r\n\r\n ctx.beginPath();\r\n ctx.roundRect(-width / 2, -height / 2, width, height, radius);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\n/**\r\n * Render a vertical pill control (for top/bottom side handles).\r\n * Modern Canva-style appearance.\r\n * @param {CanvasRenderingContext2D} ctx context to render on\r\n * @param {Number} left x coordinate where the control center should be\r\n * @param {Number} top y coordinate where the control center should be\r\n * @param {Object} styleOverride override for FabricObject controls style\r\n * @param {FabricObject} fabricObject the fabric object for which we are rendering controls\r\n */\r\nexport function renderVerticalPillControl(\r\n this: Control,\r\n ctx: CanvasRenderingContext2D,\r\n left: number,\r\n top: number,\r\n styleOverride: ControlRenderingStyleOverride,\r\n fabricObject: InteractiveFabricObject,\r\n) {\r\n styleOverride = styleOverride || {};\r\n const width = PILL_HEIGHT; // Swapped for vertical\r\n const height = PILL_WIDTH;\r\n const radius = PILL_RADIUS;\r\n\r\n ctx.save();\r\n ctx.translate(left, top);\r\n const angle = fabricObject.getTotalAngle();\r\n ctx.rotate(degreesToRadians(angle));\r\n\r\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';\r\n ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';\r\n ctx.lineWidth = 1.5;\r\n\r\n ctx.beginPath();\r\n ctx.roundRect(-width / 2, -height / 2, width, height, radius);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n"],"names":["PILL_WIDTH","PILL_HEIGHT","PILL_RADIUS","renderCircleControl","ctx","left","top","styleOverride","fabricObject","xSize","sizeX","cornerSize","ySize","sizeY","transparentCorners","methodName","STROKE","FILL","stroke","cornerStrokeColor","myLeft","myTop","size","save","fillStyle","cornerColor","strokeStyle","scale","beginPath","arc","twoMathPi","restore","renderSquareControl","xSizeBy2","ySizeBy2","translate","angle","getTotalAngle","rotate","degreesToRadians","strokeRect","renderHorizontalPillControl","width","height","radius","lineWidth","roundRect","fill","renderVerticalPillControl"],"mappings":"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"}
@@ -0,0 +1,298 @@
1
+ import type { TClassProperties, TOptions, Abortable, TCrossOrigin } from '../typedefs';
2
+ import type { FabricObject } from './Object/FabricObject';
3
+ import type { GroupProps, SerializedGroupProps } from './Group';
4
+ import { Group } from './Group';
5
+ import { FabricImage } from './Image';
6
+ /**
7
+ * Frame shape types supported out of the box
8
+ */
9
+ export type FrameShapeType = 'rect' | 'circle' | 'rounded-rect' | 'custom';
10
+ /**
11
+ * Frame metadata for persistence and state management
12
+ */
13
+ export interface FrameMeta {
14
+ /** Aspect ratio label (e.g., '16:9', '1:1', '4:5') */
15
+ aspect?: string;
16
+ /** Content scale factor for cover scaling */
17
+ contentScale?: number;
18
+ /** X offset of content within frame */
19
+ contentOffsetX?: number;
20
+ /** Y offset of content within frame */
21
+ contentOffsetY?: number;
22
+ /** Source URL of the current image */
23
+ imageSrc?: string;
24
+ /** Original image dimensions */
25
+ originalWidth?: number;
26
+ /** Original image dimensions */
27
+ originalHeight?: number;
28
+ }
29
+ /**
30
+ * Frame-specific properties
31
+ */
32
+ export interface FrameOwnProps {
33
+ /** Fixed width of the frame */
34
+ frameWidth: number;
35
+ /** Fixed height of the frame */
36
+ frameHeight: number;
37
+ /** Shape type for the clip mask */
38
+ frameShape: FrameShapeType;
39
+ /** Border radius for rounded-rect shape */
40
+ frameBorderRadius: number;
41
+ /** Custom SVG path for custom shape */
42
+ frameCustomPath?: string;
43
+ /** Frame metadata for content positioning */
44
+ frameMeta: FrameMeta;
45
+ /** Whether the frame is in edit mode (content can be repositioned) */
46
+ isEditMode: boolean;
47
+ /** Placeholder text shown when frame is empty */
48
+ placeholderText: string;
49
+ /** Placeholder background color */
50
+ placeholderColor: string;
51
+ }
52
+ export interface SerializedFrameProps extends SerializedGroupProps, FrameOwnProps {
53
+ }
54
+ export interface FrameProps extends GroupProps, FrameOwnProps {
55
+ }
56
+ export declare const frameDefaultValues: Partial<TClassProperties<Frame>>;
57
+ /**
58
+ * Frame class - A Canva-like frame container for images
59
+ *
60
+ * Features:
61
+ * - Fixed dimensions that don't change when content is added/removed
62
+ * - Multiple shape types (rect, circle, rounded-rect, custom SVG path)
63
+ * - Cover scaling: images fill the frame completely, overflow is clipped
64
+ * - Double-click edit mode: reposition/zoom content within frame
65
+ * - Drag & drop support for replacing images
66
+ * - Full serialization/deserialization support
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * // Create a rectangular frame
71
+ * const frame = new Frame([], {
72
+ * frameWidth: 300,
73
+ * frameHeight: 200,
74
+ * frameShape: 'rect',
75
+ * left: 100,
76
+ * top: 100,
77
+ * });
78
+ *
79
+ * // Add image with cover scaling
80
+ * await frame.setImage('https://example.com/image.jpg');
81
+ *
82
+ * canvas.add(frame);
83
+ * ```
84
+ */
85
+ export declare class Frame extends Group {
86
+ static type: string;
87
+ frameWidth: number;
88
+ frameHeight: number;
89
+ frameShape: FrameShapeType;
90
+ frameBorderRadius: number;
91
+ frameCustomPath?: string;
92
+ frameMeta: FrameMeta;
93
+ isEditMode: boolean;
94
+ placeholderText: string;
95
+ placeholderColor: string;
96
+ /**
97
+ * Reference to the content image
98
+ * @private
99
+ */
100
+ private _contentImage;
101
+ /**
102
+ * Reference to the placeholder object
103
+ * @private
104
+ */
105
+ private _placeholder;
106
+ static ownDefaults: Partial<TClassProperties<Frame>>;
107
+ static getDefaults(): Record<string, any>;
108
+ /**
109
+ * Constructor
110
+ * @param objects - Initial objects (typically empty for frames)
111
+ * @param options - Frame configuration options
112
+ */
113
+ constructor(objects?: FabricObject[], options?: Partial<FrameProps>);
114
+ /**
115
+ * Sets up custom controls that resize instead of scale
116
+ * This is the key to Canva-like behavior - corners resize the frame dimensions
117
+ * instead of scaling the entire group (which would stretch the image)
118
+ * @private
119
+ */
120
+ private _setupResizeControls;
121
+ /**
122
+ * Adjusts content after a resize operation (called from set override)
123
+ * @private
124
+ */
125
+ private _adjustContentAfterResize;
126
+ /**
127
+ * Updates the clip path based on the current frame shape
128
+ * @private
129
+ */
130
+ private _updateClipPath;
131
+ /**
132
+ * Creates a placeholder element for empty frames
133
+ * Shows a colored rectangle - users can customize via placeholderColor
134
+ * @private
135
+ */
136
+ private _createPlaceholder;
137
+ /**
138
+ * Removes the placeholder element
139
+ * @private
140
+ */
141
+ private _removePlaceholder;
142
+ /**
143
+ * Restores the fixed frame dimensions
144
+ * @private
145
+ */
146
+ private _restoreFixedDimensions;
147
+ /**
148
+ * Sets an image in the frame with cover scaling
149
+ *
150
+ * @param src - Image source URL
151
+ * @param options - Optional loading options
152
+ * @returns Promise that resolves when the image is loaded and set
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * await frame.setImage('https://example.com/photo.jpg');
157
+ * canvas.renderAll();
158
+ * ```
159
+ */
160
+ setImage(src: string, options?: {
161
+ crossOrigin?: TCrossOrigin;
162
+ signal?: AbortSignal;
163
+ }): Promise<void>;
164
+ /**
165
+ * Sets an image from an existing FabricImage object
166
+ *
167
+ * @param image - FabricImage instance
168
+ */
169
+ setImageObject(image: FabricImage): void;
170
+ /**
171
+ * Calculates the cover scale factor for an image
172
+ * Cover scaling ensures the image fills the frame completely
173
+ *
174
+ * @param imageWidth - Original image width
175
+ * @param imageHeight - Original image height
176
+ * @returns Scale factor to apply
177
+ * @private
178
+ */
179
+ private _calculateCoverScale;
180
+ /**
181
+ * Clears all content from the frame
182
+ * @private
183
+ */
184
+ private _clearContent;
185
+ /**
186
+ * Clears the frame content and shows placeholder
187
+ */
188
+ clearContent(): void;
189
+ /**
190
+ * Checks if the frame has image content
191
+ */
192
+ hasContent(): boolean;
193
+ /**
194
+ * Gets the current content image
195
+ */
196
+ getContentImage(): FabricImage | null;
197
+ /**
198
+ * Enters edit mode for repositioning content within the frame
199
+ * In edit mode, the content image can be dragged and scaled
200
+ */
201
+ enterEditMode(): void;
202
+ /**
203
+ * Bound constraint handler references for cleanup
204
+ * @private
205
+ */
206
+ private _boundConstrainMove?;
207
+ private _boundConstrainScale?;
208
+ /**
209
+ * Sets up constraints for edit mode - prevents gaps
210
+ * @private
211
+ */
212
+ private _setupEditModeConstraints;
213
+ /**
214
+ * Removes edit mode constraint handlers
215
+ * @private
216
+ */
217
+ private _removeEditModeConstraints;
218
+ /**
219
+ * Stored clip path before edit mode
220
+ * @private
221
+ */
222
+ private _editModeClipPath?;
223
+ /**
224
+ * Custom render to show edit mode overlay
225
+ * @override
226
+ */
227
+ render(ctx: CanvasRenderingContext2D): void;
228
+ /**
229
+ * Renders the edit mode overlay - dims area outside frame, shows frame border
230
+ * @private
231
+ */
232
+ private _renderEditModeOverlay;
233
+ /**
234
+ * Exits edit mode and saves the content position
235
+ */
236
+ exitEditMode(): void;
237
+ /**
238
+ * Toggles edit mode
239
+ */
240
+ toggleEditMode(): void;
241
+ /**
242
+ * Resizes the frame to new dimensions (Canva-like behavior)
243
+ *
244
+ * Canva behavior:
245
+ * - When frame shrinks: crops more of image (no scale change)
246
+ * - When frame grows: uncrops to show more, preserving position
247
+ * - Only scales up when image can't cover the frame anymore
248
+ *
249
+ * @param width - New frame width
250
+ * @param height - New frame height
251
+ * @param options - Resize options
252
+ */
253
+ resizeFrame(width: number, height: number, options?: {
254
+ maintainAspect?: boolean;
255
+ }): void;
256
+ /**
257
+ * Sets the frame shape
258
+ *
259
+ * @param shape - Shape type
260
+ * @param customPath - Custom SVG path for 'custom' shape type
261
+ */
262
+ setFrameShape(shape: FrameShapeType, customPath?: string): void;
263
+ /**
264
+ * Sets the border radius for rounded-rect shape
265
+ *
266
+ * @param radius - Border radius in pixels
267
+ */
268
+ setBorderRadius(radius: number): void;
269
+ /**
270
+ * Override add to maintain fixed dimensions
271
+ */
272
+ add(...objects: FabricObject[]): number;
273
+ /**
274
+ * Override remove to maintain fixed dimensions
275
+ */
276
+ remove(...objects: FabricObject[]): FabricObject[];
277
+ /**
278
+ * Override insertAt to maintain fixed dimensions
279
+ */
280
+ insertAt(index: number, ...objects: FabricObject[]): number;
281
+ /**
282
+ * Serializes the frame to a plain object
283
+ */
284
+ toObject(propertiesToInclude?: string[]): any;
285
+ /**
286
+ * Creates a Frame instance from a serialized object
287
+ */
288
+ static fromObject<T extends TOptions<SerializedFrameProps>>(object: T, abortable?: Abortable): Promise<Frame>;
289
+ /**
290
+ * Creates a Frame with a specific aspect ratio preset
291
+ *
292
+ * @param aspect - Aspect ratio preset (e.g., '16:9', '1:1', '4:5', '9:16')
293
+ * @param size - Base size in pixels
294
+ * @param options - Additional frame options
295
+ */
296
+ static createWithAspect(aspect: string, size?: number, options?: Partial<FrameProps>): Frame;
297
+ }
298
+ //# sourceMappingURL=Frame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Frame.d.ts","sourceRoot":"","sources":["../../../src/shapes/Frame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{defineProperty as t}from"../../_virtual/_rollupPluginBabelHelpers.min.mjs";import{Group as e}from"./Group.min.mjs";import{Rect as i}from"./Rect.min.mjs";import{Circle as a}from"./Circle.min.mjs";import{Path as s}from"./Path.min.mjs";import{FabricImage as r}from"./Image.min.mjs";import{classRegistry as n}from"../ClassRegistry.min.mjs";import{LayoutManager as o}from"../LayoutManager/LayoutManager.min.mjs";import{FrameLayout as h}from"../LayoutManager/LayoutStrategies/FrameLayout.min.mjs";import{enlivenObjects as l,enlivenObjectEnlivables as c}from"../util/misc/objectEnlive.min.mjs";import{Control as d}from"../controls/Control.min.mjs";import{getLocalPoint as m}from"../controls/util.min.mjs";import{wrapWithFireEvent as f}from"../controls/wrapWithFireEvent.min.mjs";import{wrapWithFixedAnchor as g}from"../controls/wrapWithFixedAnchor.min.mjs";import{RESIZING as u}from"../constants.min.mjs";const v={frameWidth:200,frameHeight:200,frameShape:"rect",frameBorderRadius:0,isEditMode:!1,placeholderText:"Drop image here",placeholderColor:"#d0d0d0",frameMeta:{contentScale:1,contentOffsetX:0,contentOffsetY:0}};class p extends e{static getDefaults(){return{...super.getDefaults(),...p.ownDefaults}}constructor(){var e,i,a;let s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const n=new o(new h);super(s,{...r,layoutManager:n}),t(this,"_contentImage",null),t(this,"_placeholder",null),t(this,"_boundConstrainMove",void 0),t(this,"_boundConstrainScale",void 0),t(this,"_editModeClipPath",void 0),Object.assign(this,p.ownDefaults),this.setOptions(r);const l=v.frameMeta||{};this.frameMeta={contentScale:null!==(e=l.contentScale)&&void 0!==e?e:1,contentOffsetX:null!==(i=l.contentOffsetX)&&void 0!==i?i:0,contentOffsetY:null!==(a=l.contentOffsetY)&&void 0!==a?a:0,...r.frameMeta},this.set({width:this.frameWidth,height:this.frameHeight}),this._updateClipPath(),0===s.length&&this._createPlaceholder(),this._setupResizeControls()}_setupResizeControls(){const t=f(u,g((t,e,i,a)=>{const s=e.target,r=m(e,e.originX,e.originY,i,a),n=s.frameWidth,o=s.frameHeight,h=Math.max(20,Math.abs(r.x)),l=Math.max(20,Math.abs(r.y));return!(Math.abs(n-h)<1&&Math.abs(o-l)<1)&&(s.frameWidth=h,s.frameHeight=l,s.width=h,s.height=l,s._updateClipPath(),s._adjustContentAfterResize(),!0)})),e=f(u,g((t,e,i,a)=>{const s=e.target,r=m(e,e.originX,e.originY,i,a),n=s.frameWidth,o=Math.max(20,Math.abs(r.x));return!(Math.abs(n-o)<1)&&(s.frameWidth=o,s.width=o,s._updateClipPath(),s._adjustContentAfterResize(),!0)})),i=f(u,g((t,e,i,a)=>{const s=e.target,r=m(e,e.originX,e.originY,i,a),n=s.frameHeight,o=Math.max(20,Math.abs(r.y));return!(Math.abs(n-o)<1)&&(s.frameHeight=o,s.height=o,s._updateClipPath(),s._adjustContentAfterResize(),!0)}));if(!this.controls)return void console.warn("Frame: controls not initialized yet");["tl","tr","bl","br"].forEach(e=>{const i=this.controls[e];i&&(this.controls[e]=new d({x:i.x,y:i.y,cursorStyleHandler:i.cursorStyleHandler,actionHandler:t,actionName:"resizing"}))});["ml","mr"].forEach(t=>{const i=this.controls[t];i&&(this.controls[t]=new d({x:i.x,y:i.y,cursorStyleHandler:i.cursorStyleHandler,actionHandler:e,actionName:"resizing",render:i.render,sizeX:i.sizeX,sizeY:i.sizeY}))});["mt","mb"].forEach(t=>{const e=this.controls[t];e&&(this.controls[t]=new d({x:e.x,y:e.y,cursorStyleHandler:e.cursorStyleHandler,actionHandler:i,actionName:"resizing",render:e.render,sizeX:e.sizeX,sizeY:e.sizeY}))})}_adjustContentAfterResize(){if(this._placeholder&&this._placeholder.set({width:this.frameWidth,height:this.frameHeight}),this._contentImage){var t,e,i,a,s,r,n;const o=this._contentImage,h=null!==(t=null!==(e=this.frameMeta.originalWidth)&&void 0!==e?e:o.width)&&void 0!==t?t:100,l=null!==(i=null!==(a=this.frameMeta.originalHeight)&&void 0!==a?a:o.height)&&void 0!==i?i:100;let c=null!==(s=o.scaleX)&&void 0!==s?s:1,d=null!==(r=o.left)&&void 0!==r?r:0,m=null!==(n=o.top)&&void 0!==n?n:0;const f=this._calculateCoverScale(h,l);if(c<f){const t=f/c;d*=t,m*=t,c=f,o.set({scaleX:c,scaleY:c}),this.frameMeta={...this.frameMeta,contentScale:c}}const g=h*c/2,u=l*c/2,v=this.frameWidth/2,p=this.frameHeight/2,M=Math.max(0,g-v),_=Math.max(0,u-p),C=Math.abs(d)>M,b=Math.abs(m)>_;C&&(d=Math.max(-M,Math.min(M,d))),b&&(m=Math.max(-_,Math.min(_,m))),(C||b)&&(o.set({left:d,top:m}),this.frameMeta={...this.frameMeta,contentOffsetX:d,contentOffsetY:m}),o.setCoords()}this.setCoords()}_updateClipPath(){let t;switch(this.frameShape){case"circle":{const e=Math.min(this.frameWidth,this.frameHeight)/2;t=new a({radius:e,originX:"center",originY:"center",left:0,top:0});break}case"rounded-rect":t=new i({width:this.frameWidth,height:this.frameHeight,rx:this.frameBorderRadius,ry:this.frameBorderRadius,originX:"center",originY:"center",left:0,top:0});break;case"custom":if(this.frameCustomPath){t=new s(this.frameCustomPath,{originX:"center",originY:"center",left:0,top:0});const e=t.getBoundingRect(),i=this.frameWidth/e.width,a=this.frameHeight/e.height;t.set({scaleX:i,scaleY:a})}else t=new i({width:this.frameWidth,height:this.frameHeight,originX:"center",originY:"center",left:0,top:0});break;default:t=new i({width:this.frameWidth,height:this.frameHeight,originX:"center",originY:"center",left:0,top:0})}this.clipPath=t,this.set("dirty",!0)}_createPlaceholder(){this._placeholder&&(super.remove(this._placeholder),this._placeholder=null);const t=new i({width:this.frameWidth,height:this.frameHeight,fill:this.placeholderColor,originX:"center",originY:"center",left:0,top:0,selectable:!1,evented:!1});this._placeholder=t,super.add(t),this._restoreFixedDimensions()}_removePlaceholder(){this._placeholder&&(super.remove(this._placeholder),this._placeholder=null)}_restoreFixedDimensions(){this.set({width:this.frameWidth,height:this.frameHeight})}async setImage(t){var e,i;let a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const{crossOrigin:s="anonymous",signal:n}=a,o=await r.fromURL(t,{crossOrigin:s,signal:n}),h=null!==(e=o.width)&&void 0!==e?e:100,l=null!==(i=o.height)&&void 0!==i?i:100,c=this._calculateCoverScale(h,l);o.set({scaleX:c,scaleY:c,originX:"center",originY:"center",left:0,top:0,selectable:!1,evented:!1}),this._clearContent(),this._contentImage=o,super.add(o),this._contentImage.set({left:0,top:0}),this.frameMeta={...this.frameMeta,contentScale:c,contentOffsetX:0,contentOffsetY:0,imageSrc:t,originalWidth:h,originalHeight:l},this._restoreFixedDimensions(),this.setCoords(),this._contentImage.setCoords(),this.set("dirty",!0)}setImageObject(t){var e,i;const a=null!==(e=t.width)&&void 0!==e?e:100,s=null!==(i=t.height)&&void 0!==i?i:100,r=this._calculateCoverScale(a,s);t.set({scaleX:r,scaleY:r,originX:"center",originY:"center",left:0,top:0,selectable:!1,evented:!1}),this._clearContent(),this._contentImage=t,super.add(t),this.frameMeta={...this.frameMeta,contentScale:r,contentOffsetX:0,contentOffsetY:0,imageSrc:t.getSrc(),originalWidth:a,originalHeight:s},this._restoreFixedDimensions(),this.set("dirty",!0)}_calculateCoverScale(t,e){const i=this.frameWidth/t,a=this.frameHeight/e;return Math.max(i,a)}_clearContent(){this._removePlaceholder(),this._contentImage&&(super.remove(this._contentImage),this._contentImage=null);this.getObjects().forEach(t=>super.remove(t))}clearContent(){this._clearContent(),this._createPlaceholder(),this.frameMeta={contentScale:1,contentOffsetX:0,contentOffsetY:0},this.set("dirty",!0)}hasContent(){return null!==this._contentImage}getContentImage(){return this._contentImage}enterEditMode(){var t,e,i,a;if(!this._contentImage||this.isEditMode)return;this.isEditMode=!0,this.subTargetCheck=!0,this.interactive=!0;const s=null!==(t=null!==(e=this.frameMeta.originalWidth)&&void 0!==e?e:this._contentImage.width)&&void 0!==t?t:100,r=null!==(i=null!==(a=this.frameMeta.originalHeight)&&void 0!==a?a:this._contentImage.height)&&void 0!==i?i:100,n=this._calculateCoverScale(s,r);this._contentImage.set({selectable:!0,evented:!0,hasControls:!0,hasBorders:!0,minScaleLimit:n,lockScalingFlip:!0}),this.clipPath&&(this._editModeClipPath=this.clipPath,this.clipPath=void 0),this._setupEditModeConstraints(),this.set("dirty",!0),this.canvas&&(this.canvas.setActiveObject(this._contentImage),this.canvas.renderAll()),this.fire("frame:editmode:enter",{target:this})}_setupEditModeConstraints(){if(!this._contentImage||!this.canvas)return;const t=this,e=this._contentImage;this._boundConstrainMove=i=>{var a,s,r,n,o,h,l;if(i.target!==e||!t.isEditMode)return;const c=null!==(a=null!==(s=t.frameMeta.originalWidth)&&void 0!==s?s:e.width)&&void 0!==a?a:100,d=null!==(r=null!==(n=t.frameMeta.originalHeight)&&void 0!==n?n:e.height)&&void 0!==r?r:100,m=null!==(o=e.scaleX)&&void 0!==o?o:1,f=c*m/2,g=d*m/2,u=t.frameWidth/2,v=t.frameHeight/2,p=Math.max(0,f-u),M=Math.max(0,g-v);let _=null!==(h=e.left)&&void 0!==h?h:0,C=null!==(l=e.top)&&void 0!==l?l:0;_=Math.max(-p,Math.min(p,_)),C=Math.max(-M,Math.min(M,C)),e.set({left:_,top:C})},this._boundConstrainScale=i=>{var a,s,r,n,o,h,l;if(i.target!==e||!t.isEditMode)return;const c=null!==(a=null!==(s=t.frameMeta.originalWidth)&&void 0!==s?s:e.width)&&void 0!==a?a:100,d=null!==(r=null!==(n=t.frameMeta.originalHeight)&&void 0!==n?n:e.height)&&void 0!==r?r:100,m=t._calculateCoverScale(c,d);let f=null!==(o=e.scaleX)&&void 0!==o?o:1,g=null!==(h=e.scaleY)&&void 0!==h?h:1;const u=Math.max(m,Math.max(f,g));e.set({scaleX:u,scaleY:u}),null===(l=t._boundConstrainMove)||void 0===l||l.call(t,i)},this.canvas.on("object:moving",this._boundConstrainMove),this.canvas.on("object:scaling",this._boundConstrainScale)}_removeEditModeConstraints(){this.canvas&&(this._boundConstrainMove&&(this.canvas.off("object:moving",this._boundConstrainMove),this._boundConstrainMove=void 0),this._boundConstrainScale&&(this.canvas.off("object:scaling",this._boundConstrainScale),this._boundConstrainScale=void 0))}render(t){super.render(t),this.isEditMode&&this._editModeClipPath&&this._renderEditModeOverlay(t)}_renderEditModeOverlay(t){t.save();const e=this.calcTransformMatrix();t.transform(e[0],e[1],e[2],e[3],e[4],e[5]),t.beginPath();if(t.rect(-2e3,-2e3,4e3,4e3),"circle"===this.frameShape){const e=Math.min(this.frameWidth,this.frameHeight)/2;t.moveTo(e,0),t.arc(0,0,e,0,2*Math.PI,!0)}else if("rounded-rect"===this.frameShape){const e=this.frameWidth/2,i=this.frameHeight/2,a=Math.min(this.frameBorderRadius,e,i);t.moveTo(e,i-a),t.arcTo(e,-i,e-a,-i,a),t.arcTo(-e,-i,-e,-i+a,a),t.arcTo(-e,i,-e+a,i,a),t.arcTo(e,i,e,i-a,a),t.closePath()}else{const e=this.frameWidth/2,i=this.frameHeight/2;t.moveTo(e,-i),t.lineTo(-e,-i),t.lineTo(-e,i),t.lineTo(e,i),t.closePath()}if(t.fillStyle="rgba(0, 0, 0, 0.5)",t.fill("evenodd"),t.beginPath(),"circle"===this.frameShape){const e=Math.min(this.frameWidth,this.frameHeight)/2;t.arc(0,0,e,0,2*Math.PI)}else if("rounded-rect"===this.frameShape){const e=this.frameWidth/2,i=this.frameHeight/2,a=Math.min(this.frameBorderRadius,e,i);t.moveTo(e-a,-i),t.arcTo(e,-i,e,-i+a,a),t.arcTo(e,i,e-a,i,a),t.arcTo(-e,i,-e,i-a,a),t.arcTo(-e,-i,-e+a,-i,a),t.closePath()}else{const e=this.frameWidth/2,i=this.frameHeight/2;t.rect(-e,-i,this.frameWidth,this.frameHeight)}t.strokeStyle="rgba(255, 255, 255, 0.8)",t.lineWidth=2,t.stroke(),t.setLineDash([5,5]),t.strokeStyle="rgba(0, 150, 255, 0.8)",t.lineWidth=1,t.stroke(),t.restore()}exitEditMode(){var t,e,i,a,s,r,n,o;if(!this._contentImage||!this.isEditMode)return;this.isEditMode=!1,this._removeEditModeConstraints(),this.subTargetCheck=!1,this.interactive=!1;const h=null!==(t=this._contentImage.left)&&void 0!==t?t:0,l=null!==(e=this._contentImage.top)&&void 0!==e?e:0,c=null!==(i=this._contentImage.scaleX)&&void 0!==i?i:1,d=null!==(a=this._contentImage.scaleY)&&void 0!==a?a:1,m=null!==(s=null!==(r=this.frameMeta.originalWidth)&&void 0!==r?r:this._contentImage.width)&&void 0!==s?s:100,f=null!==(n=null!==(o=this.frameMeta.originalHeight)&&void 0!==o?o:this._contentImage.height)&&void 0!==n?n:100,g=Math.max(c,d),u=m*g/2,v=f*g/2,p=this.frameWidth/2,M=this.frameHeight/2,_=Math.max(0,u-p),C=Math.max(0,v-M),b=Math.max(-_,Math.min(_,h)),S=Math.max(-C,Math.min(C,l));this._contentImage.set({left:b,top:S}),this.frameMeta={...this.frameMeta,contentOffsetX:b,contentOffsetY:S,contentScale:g},this._contentImage.set({selectable:!1,evented:!1,hasControls:!1,hasBorders:!1}),this._editModeClipPath?(this.clipPath=this._editModeClipPath,this._editModeClipPath=void 0):this._updateClipPath(),this.set("dirty",!0),this.canvas&&(this.canvas.setActiveObject(this),this.canvas.renderAll()),this.fire("frame:editmode:exit",{target:this})}toggleEditMode(){this.isEditMode?this.exitEditMode():this.enterEditMode()}resizeFrame(t,e){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};const{maintainAspect:a=!1}=i;if(a){const i=this.frameWidth/this.frameHeight;t/e>i?e=t/i:t=e*i}this.frameWidth=t,this.frameHeight=e,super.set({width:this.frameWidth,height:this.frameHeight}),this._updateClipPath(),this._adjustContentAfterResize(),this.set("dirty",!0),this.setCoords()}setFrameShape(t,e){this.frameShape=t,e&&(this.frameCustomPath=e),this._updateClipPath(),this.set("dirty",!0)}setBorderRadius(t){this.frameBorderRadius=t,"rounded-rect"===this.frameShape&&(this._updateClipPath(),this.set("dirty",!0))}add(){const t=super.add(...arguments);return this._restoreFixedDimensions(),t}remove(){const t=super.remove(...arguments);return this._restoreFixedDimensions(),t}insertAt(t){for(var e=arguments.length,i=new Array(e>1?e-1:0),a=1;a<e;a++)i[a-1]=arguments[a];const s=super.insertAt(t,...i);return this._restoreFixedDimensions(),s}toObject(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{...super.toObject(t),frameWidth:this.frameWidth,frameHeight:this.frameHeight,frameShape:this.frameShape,frameBorderRadius:this.frameBorderRadius,frameCustomPath:this.frameCustomPath,frameMeta:{...this.frameMeta},isEditMode:!1,placeholderText:this.placeholderText,placeholderColor:this.placeholderColor}}static fromObject(t,e){const{objects:i=[],layoutManager:a,frameWidth:s,frameHeight:r,frameShape:n,frameBorderRadius:o,frameCustomPath:h,frameMeta:d,placeholderText:m,placeholderColor:f,...g}=t;return Promise.all([l(i,e),c(g,e)]).then(t=>{var e,i,a;let[l,c]=t;const u=new p([],{...g,...c,frameWidth:s,frameHeight:r,frameShape:n,frameBorderRadius:o,frameCustomPath:h,frameMeta:d?{contentScale:null!==(e=d.contentScale)&&void 0!==e?e:1,contentOffsetX:null!==(i=d.contentOffsetX)&&void 0!==i?i:0,contentOffsetY:null!==(a=d.contentOffsetY)&&void 0!==a?a:0,...d}:void 0,placeholderText:m,placeholderColor:f});return null!=d&&d.imageSrc&&u.setImage(d.imageSrc).then(()=>{var t,e,i,a;u._contentImage&&u._contentImage.set({left:null!==(t=d.contentOffsetX)&&void 0!==t?t:0,top:null!==(e=d.contentOffsetY)&&void 0!==e?e:0,scaleX:null!==(i=d.contentScale)&&void 0!==i?i:1,scaleY:null!==(a=d.contentScale)&&void 0!==a?a:1});u.set("dirty",!0)}).catch(t=>{console.warn("Failed to restore frame image:",t)}),u})}static createWithAspect(t){var e,i,a;let s,r,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:200,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};switch(t){case"16:9":s=n,r=n*(9/16);break;case"9:16":s=n*(9/16),r=n;break;case"4:5":s=.8*n,r=n;break;case"4:3":s=n,r=n*(3/4);break;case"3:4":s=n*(3/4),r=n;break;default:s=n,r=n}const h=v.frameMeta||{};return new p([],{...o,frameWidth:s,frameHeight:r,frameMeta:{contentScale:null!==(e=h.contentScale)&&void 0!==e?e:1,contentOffsetX:null!==(i=h.contentOffsetX)&&void 0!==i?i:0,contentOffsetY:null!==(a=h.contentOffsetY)&&void 0!==a?a:0,aspect:t,...o.frameMeta}})}}t(p,"type","Frame"),t(p,"ownDefaults",v),n.setClass(p),n.setClass(p,"frame");export{p as Frame,v as frameDefaultValues};
2
+ //# sourceMappingURL=Frame.min.mjs.map