@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.
- package/.history/package_20251226051014.json +164 -0
- package/.history/package_20251226164045.json +164 -0
- package/dist/fabric.d.ts +2 -0
- package/dist/fabric.d.ts.map +1 -1
- package/dist/fabric.min.mjs +1 -1
- package/dist/fabric.mjs +2 -0
- package/dist/fabric.mjs.map +1 -1
- package/dist/index.js +1760 -368
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +1759 -369
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +1760 -368
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +1759 -369
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.json.min.mjs +1 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts +31 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts.map +1 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.min.mjs +2 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.min.mjs.map +1 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.mjs +81 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.mjs.map +1 -0
- package/dist/src/LayoutManager/index.d.ts +1 -0
- package/dist/src/LayoutManager/index.d.ts.map +1 -1
- package/dist/src/controls/Control.d.ts.map +1 -1
- package/dist/src/controls/Control.min.mjs +1 -1
- package/dist/src/controls/Control.min.mjs.map +1 -1
- package/dist/src/controls/Control.mjs +19 -1
- package/dist/src/controls/Control.mjs.map +1 -1
- package/dist/src/controls/commonControls.d.ts.map +1 -1
- package/dist/src/controls/commonControls.min.mjs +1 -1
- package/dist/src/controls/commonControls.min.mjs.map +1 -1
- package/dist/src/controls/commonControls.mjs +25 -6
- package/dist/src/controls/commonControls.mjs.map +1 -1
- package/dist/src/controls/controlRendering.d.ts +20 -0
- package/dist/src/controls/controlRendering.d.ts.map +1 -1
- package/dist/src/controls/controlRendering.min.mjs +1 -1
- package/dist/src/controls/controlRendering.min.mjs.map +1 -1
- package/dist/src/controls/controlRendering.mjs +63 -1
- package/dist/src/controls/controlRendering.mjs.map +1 -1
- package/dist/src/shapes/Frame.d.ts +298 -0
- package/dist/src/shapes/Frame.d.ts.map +1 -0
- package/dist/src/shapes/Frame.min.mjs +2 -0
- package/dist/src/shapes/Frame.min.mjs.map +1 -0
- package/dist/src/shapes/Frame.mjs +1236 -0
- package/dist/src/shapes/Frame.mjs.map +1 -0
- package/dist/src/shapes/Object/defaultValues.d.ts.map +1 -1
- package/dist/src/shapes/Object/defaultValues.min.mjs +1 -1
- package/dist/src/shapes/Object/defaultValues.min.mjs.map +1 -1
- package/dist/src/shapes/Object/defaultValues.mjs +8 -7
- package/dist/src/shapes/Object/defaultValues.mjs.map +1 -1
- package/dist-extensions/fabric.d.ts +2 -0
- package/dist-extensions/fabric.d.ts.map +1 -1
- package/dist-extensions/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts +31 -0
- package/dist-extensions/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts.map +1 -0
- package/dist-extensions/src/LayoutManager/index.d.ts +1 -0
- package/dist-extensions/src/LayoutManager/index.d.ts.map +1 -1
- package/dist-extensions/src/controls/Control.d.ts.map +1 -1
- package/dist-extensions/src/controls/commonControls.d.ts.map +1 -1
- package/dist-extensions/src/controls/controlRendering.d.ts +20 -0
- package/dist-extensions/src/controls/controlRendering.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Frame.d.ts +298 -0
- package/dist-extensions/src/shapes/Frame.d.ts.map +1 -0
- package/dist-extensions/src/shapes/Object/defaultValues.d.ts.map +1 -1
- package/fabric.ts +8 -0
- package/package.json +1 -1
- package/src/LayoutManager/LayoutStrategies/FrameLayout.ts +80 -0
- package/src/LayoutManager/index.ts +1 -0
- package/src/controls/Control.ts +40 -1
- package/src/controls/commonControls.ts +22 -0
- package/src/controls/controlRendering.ts +83 -0
- package/src/shapes/Frame.ts +1361 -0
- 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;
|
|
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
|
|
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
|
-
|
|
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
|