@erase2d/fabric 1.1.0 → 1.1.1

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.
@@ -0,0 +1,117 @@
1
+ import { toConsumableArray as _toConsumableArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
2
+ import { Group } from 'fabric';
3
+ import { ClippingGroup } from './ClippingGroup.js';
4
+
5
+ function walk(objects) {
6
+ return objects.flatMap(function (object) {
7
+ if (!object.erasable || object.isNotVisible()) {
8
+ return [];
9
+ } else if (object instanceof Group && object.erasable === 'deep') {
10
+ return walk(object.getObjects());
11
+ } else {
12
+ return [object];
13
+ }
14
+ });
15
+ }
16
+ function drawCanvas(ctx, canvas, objects) {
17
+ canvas.clearContext(ctx);
18
+ ctx.imageSmoothingEnabled = canvas.imageSmoothingEnabled;
19
+ ctx.imageSmoothingQuality = 'high';
20
+ // @ts-expect-error node-canvas stuff
21
+ ctx.patternQuality = 'best';
22
+ canvas._renderBackground(ctx);
23
+ ctx.save();
24
+ ctx.transform.apply(ctx, _toConsumableArray(canvas.viewportTransform));
25
+ objects.forEach(function (object) {
26
+ return object.render(ctx);
27
+ });
28
+ ctx.restore();
29
+ var clipPath = canvas.clipPath;
30
+ if (clipPath) {
31
+ // fabric crap
32
+ clipPath._set('canvas', canvas);
33
+ clipPath.shouldCache();
34
+ clipPath._transformDone = true;
35
+ clipPath.renderCache({
36
+ forClipping: true
37
+ });
38
+ canvas.drawClipPathOnCanvas(ctx, clipPath);
39
+ }
40
+ canvas._renderOverlay(ctx);
41
+ }
42
+
43
+ /**
44
+ * Prepare the pattern for the erasing brush
45
+ * This pattern will be drawn on the top context after clipping the main context,
46
+ * achieving a visual effect of erasing only erasable objects.
47
+ *
48
+ * This is designed to support erasing a collection with both erasable and non-erasable objects while maintaining object stacking.\
49
+ * Iterates over collections to allow nested selective erasing.\
50
+ * Prepares objects before rendering the pattern brush.\
51
+ * If brush is **NOT** inverted render all non-erasable objects.\
52
+ * If brush is inverted render all objects, erasable objects without their eraser.
53
+ * This will render the erased parts as if they were not erased in the first place, achieving an undo effect.
54
+ *
55
+ * Caveat:
56
+ * Does not support erasing effects of shadows
57
+ *
58
+ */
59
+ function draw(ctx, _ref, _ref2) {
60
+ var inverted = _ref.inverted,
61
+ opacity = _ref.opacity;
62
+ var canvas = _ref2.canvas,
63
+ _ref2$objects = _ref2.objects,
64
+ objects = _ref2$objects === void 0 ? canvas._objectsToRender || canvas._objects : _ref2$objects,
65
+ _ref2$background = _ref2.background,
66
+ background = _ref2$background === void 0 ? canvas.backgroundImage : _ref2$background,
67
+ _ref2$overlay = _ref2.overlay,
68
+ overlay = _ref2$overlay === void 0 ? canvas.overlayImage : _ref2$overlay;
69
+ // prepare tree
70
+ var alpha = 1 - opacity;
71
+ var restore = walk([].concat(_toConsumableArray(objects), _toConsumableArray([background, overlay].filter(function (d) {
72
+ return !!d;
73
+ })))).map(function (object) {
74
+ if (!inverted) {
75
+ var _object$parent;
76
+ // render only non-erasable objects
77
+ var _opacity = object.opacity;
78
+ object.opacity *= alpha;
79
+ (_object$parent = object.parent) === null || _object$parent === void 0 || _object$parent.set('dirty', true);
80
+ return {
81
+ object: object,
82
+ opacity: _opacity
83
+ };
84
+ } else if (object.clipPath instanceof ClippingGroup) {
85
+ // render all objects without eraser
86
+ object.clipPath['blockErasing'] = true;
87
+ object.clipPath.set('dirty', true);
88
+ object.set('dirty', true);
89
+ return {
90
+ object: object,
91
+ clipPath: object.clipPath
92
+ };
93
+ }
94
+ });
95
+
96
+ // draw
97
+ drawCanvas(ctx, canvas, objects);
98
+
99
+ // restore
100
+ restore.forEach(function (entry) {
101
+ if (!entry) {
102
+ return;
103
+ }
104
+ if (entry.opacity) {
105
+ var _entry$object$parent;
106
+ entry.object.opacity = opacity;
107
+ (_entry$object$parent = entry.object.parent) === null || _entry$object$parent === void 0 || _entry$object$parent.set('dirty', true);
108
+ } else if (entry.clipPath) {
109
+ entry.clipPath['blockErasing'] = false;
110
+ entry.clipPath.set('dirty', true);
111
+ entry.object.set('dirty', true);
112
+ }
113
+ });
114
+ }
115
+
116
+ export { draw };
117
+ //# sourceMappingURL=ErasingEffect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErasingEffect.js","sources":["../../../src/ErasingEffect.ts"],"sourcesContent":["import { Canvas, FabricObject, Group } from 'fabric';\nimport { ClippingGroup } from './ClippingGroup';\n\nfunction walk(objects: FabricObject[]): FabricObject[] {\n return objects.flatMap((object) => {\n if (!object.erasable || object.isNotVisible()) {\n return [];\n } else if (object instanceof Group && object.erasable === 'deep') {\n return walk(object.getObjects());\n } else {\n return [object];\n }\n });\n}\n\nfunction drawCanvas(\n ctx: CanvasRenderingContext2D,\n canvas: Canvas,\n objects: FabricObject[]\n) {\n canvas.clearContext(ctx);\n\n ctx.imageSmoothingEnabled = canvas.imageSmoothingEnabled;\n ctx.imageSmoothingQuality = 'high';\n // @ts-expect-error node-canvas stuff\n ctx.patternQuality = 'best';\n\n canvas._renderBackground(ctx);\n\n ctx.save();\n ctx.transform(...canvas.viewportTransform);\n objects.forEach((object) => object.render(ctx));\n ctx.restore();\n\n const clipPath = canvas.clipPath;\n if (clipPath) {\n // fabric crap\n clipPath._set('canvas', canvas);\n clipPath.shouldCache();\n clipPath._transformDone = true;\n clipPath.renderCache({ forClipping: true });\n canvas.drawClipPathOnCanvas(ctx, clipPath as any);\n }\n\n canvas._renderOverlay(ctx);\n}\n\n/**\n * Prepare the pattern for the erasing brush\n * This pattern will be drawn on the top context after clipping the main context,\n * achieving a visual effect of erasing only erasable objects.\n *\n * This is designed to support erasing a collection with both erasable and non-erasable objects while maintaining object stacking.\\\n * Iterates over collections to allow nested selective erasing.\\\n * Prepares objects before rendering the pattern brush.\\\n * If brush is **NOT** inverted render all non-erasable objects.\\\n * If brush is inverted render all objects, erasable objects without their eraser.\n * This will render the erased parts as if they were not erased in the first place, achieving an undo effect.\n *\n * Caveat:\n * Does not support erasing effects of shadows\n *\n */\nexport function draw(\n ctx: CanvasRenderingContext2D,\n { inverted, opacity }: { inverted: boolean; opacity: number },\n {\n canvas,\n objects = canvas._objectsToRender || canvas._objects,\n background = canvas.backgroundImage,\n overlay = canvas.overlayImage,\n }: {\n canvas: Canvas;\n objects?: FabricObject[];\n background?: FabricObject;\n overlay?: FabricObject;\n }\n) {\n // prepare tree\n const alpha = 1 - opacity;\n const restore = walk([\n ...objects,\n ...([background, overlay] as FabricObject[]).filter((d) => !!d),\n ]).map((object) => {\n if (!inverted) {\n // render only non-erasable objects\n const opacity = object.opacity;\n object.opacity *= alpha;\n object.parent?.set('dirty', true);\n return { object, opacity };\n } else if (object.clipPath instanceof ClippingGroup) {\n // render all objects without eraser\n object.clipPath['blockErasing'] = true;\n object.clipPath.set('dirty', true);\n object.set('dirty', true);\n return { object, clipPath: object.clipPath };\n }\n });\n\n // draw\n drawCanvas(ctx, canvas, objects);\n\n // restore\n restore.forEach((entry) => {\n if (!entry) {\n return;\n }\n if (entry.opacity) {\n entry.object.opacity = opacity;\n entry.object.parent?.set('dirty', true);\n } else if (entry.clipPath) {\n entry.clipPath['blockErasing'] = false;\n entry.clipPath.set('dirty', true);\n entry.object.set('dirty', true);\n }\n });\n}\n"],"names":["walk","objects","flatMap","object","erasable","isNotVisible","Group","getObjects","drawCanvas","ctx","canvas","clearContext","imageSmoothingEnabled","imageSmoothingQuality","patternQuality","_renderBackground","save","transform","apply","_toConsumableArray","viewportTransform","forEach","render","restore","clipPath","_set","shouldCache","_transformDone","renderCache","forClipping","drawClipPathOnCanvas","_renderOverlay","draw","_ref","_ref2","inverted","opacity","_ref2$objects","_objectsToRender","_objects","_ref2$background","background","backgroundImage","_ref2$overlay","overlay","overlayImage","alpha","concat","filter","d","map","_object$parent","parent","set","ClippingGroup","entry","_entry$object$parent"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ var messageID = -1;
2
+ var isImageDataTransparent = function isImageDataTransparent(imageData) {
3
+ return imageData.data.every(function (x, i) {
4
+ return i % 4 !== 3 || x === 0;
5
+ });
6
+ };
7
+ function isTransparent(object, worker) {
8
+ // should also move to offscreen
9
+ var canvas = object.toCanvasElement({
10
+ // multiplier: 0.1,
11
+ enableRetinaScaling: false,
12
+ viewportTransform: false,
13
+ withoutTransform: true,
14
+ withoutShadow: true
15
+ });
16
+ var id = ++messageID;
17
+ return new Promise(function (resolve, reject) {
18
+ var _canvas$getContext;
19
+ var imageData = (_canvas$getContext = canvas.getContext('2d')) === null || _canvas$getContext === void 0 ? void 0 : _canvas$getContext.getImageData(0, 0, canvas.width, canvas.height);
20
+ if (!imageData) {
21
+ reject();
22
+ } else if (!worker) {
23
+ resolve(isImageDataTransparent(imageData));
24
+ } else {
25
+ var messageHandler = function messageHandler(e) {
26
+ if (e.data.messageID === id) {
27
+ worker.removeEventListener('message', messageHandler);
28
+ resolve(e.data.isTransparent);
29
+ }
30
+ };
31
+ worker.addEventListener('message', messageHandler);
32
+ worker.postMessage({
33
+ imageData: imageData,
34
+ messageID: id
35
+ }, []);
36
+ }
37
+ });
38
+ }
39
+ isTransparent.installWorker = function installWorker() {
40
+ addEventListener('message', function (e) {
41
+ var _e$data = e.data,
42
+ imageData = _e$data.imageData,
43
+ messageID = _e$data.messageID;
44
+ postMessage({
45
+ isTransparent: isImageDataTransparent(imageData),
46
+ messageID: messageID
47
+ });
48
+ });
49
+ };
50
+
51
+ export { isTransparent };
52
+ //# sourceMappingURL=isTransparent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isTransparent.js","sources":["../../../src/isTransparent.ts"],"sourcesContent":["import { type FabricObject } from 'fabric';\n\nlet messageID = -1;\n\nconst isImageDataTransparent = (imageData: ImageData) =>\n imageData.data.every((x, i) => i % 4 !== 3 || x === 0);\n\nfunction isTransparent(object: FabricObject, worker?: Worker) {\n // should also move to offscreen\n const canvas = object.toCanvasElement({\n // multiplier: 0.1,\n enableRetinaScaling: false,\n viewportTransform: false,\n withoutTransform: true,\n withoutShadow: true,\n });\n\n const id = ++messageID;\n return new Promise<boolean>((resolve, reject) => {\n const imageData = canvas\n .getContext('2d')\n ?.getImageData(0, 0, canvas.width, canvas.height);\n\n if (!imageData) {\n reject();\n } else if (!worker) {\n resolve(isImageDataTransparent(imageData));\n } else {\n const messageHandler = (\n e: MessageEvent<{ messageID: number; isTransparent: boolean }>\n ) => {\n if (e.data.messageID === id) {\n worker.removeEventListener('message', messageHandler);\n resolve(e.data.isTransparent);\n }\n };\n worker.addEventListener('message', messageHandler);\n worker.postMessage(\n {\n imageData,\n messageID: id,\n },\n []\n );\n }\n });\n}\n\nisTransparent.installWorker = function installWorker() {\n addEventListener(\n 'message',\n (e: MessageEvent<{ imageData: ImageData; messageID: number }>) => {\n const { imageData, messageID } = e.data;\n postMessage({\n isTransparent: isImageDataTransparent(imageData),\n messageID,\n });\n }\n );\n};\n\nexport { isTransparent };\n"],"names":["messageID","isImageDataTransparent","imageData","data","every","x","i","isTransparent","object","worker","canvas","toCanvasElement","enableRetinaScaling","viewportTransform","withoutTransform","withoutShadow","id","Promise","resolve","reject","_canvas$getContext","getContext","getImageData","width","height","messageHandler","e","removeEventListener","addEventListener","postMessage","installWorker","_e$data"],"mappings":"AAEA,IAAIA,SAAS,GAAG,CAAC,CAAC,CAAA;AAElB,IAAMC,sBAAsB,GAAG,SAAzBA,sBAAsBA,CAAIC,SAAoB,EAAA;EAAA,OAClDA,SAAS,CAACC,IAAI,CAACC,KAAK,CAAC,UAACC,CAAC,EAAEC,CAAC,EAAA;IAAA,OAAKA,CAAC,GAAG,CAAC,KAAK,CAAC,IAAID,CAAC,KAAK,CAAC,CAAA;GAAC,CAAA,CAAA;AAAA,CAAA,CAAA;AAExD,SAASE,aAAaA,CAACC,MAAoB,EAAEC,MAAe,EAAE;AAC5D;AACA,EAAA,IAAMC,MAAM,GAAGF,MAAM,CAACG,eAAe,CAAC;AACpC;AACAC,IAAAA,mBAAmB,EAAE,KAAK;AAC1BC,IAAAA,iBAAiB,EAAE,KAAK;AACxBC,IAAAA,gBAAgB,EAAE,IAAI;AACtBC,IAAAA,aAAa,EAAE,IAAA;AACjB,GAAC,CAAC,CAAA;EAEF,IAAMC,EAAE,GAAG,EAAEhB,SAAS,CAAA;AACtB,EAAA,OAAO,IAAIiB,OAAO,CAAU,UAACC,OAAO,EAAEC,MAAM,EAAK;AAAA,IAAA,IAAAC,kBAAA,CAAA;AAC/C,IAAA,IAAMlB,SAAS,GAAA,CAAAkB,kBAAA,GAAGV,MAAM,CACrBW,UAAU,CAAC,IAAI,CAAC,MAAAD,IAAAA,IAAAA,kBAAA,KADDA,KAAAA,CAAAA,GAAAA,KAAAA,CAAAA,GAAAA,kBAAA,CAEdE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAEZ,MAAM,CAACa,KAAK,EAAEb,MAAM,CAACc,MAAM,CAAC,CAAA;IAEnD,IAAI,CAACtB,SAAS,EAAE;AACdiB,MAAAA,MAAM,EAAE,CAAA;AACV,KAAC,MAAM,IAAI,CAACV,MAAM,EAAE;AAClBS,MAAAA,OAAO,CAACjB,sBAAsB,CAACC,SAAS,CAAC,CAAC,CAAA;AAC5C,KAAC,MAAM;AACL,MAAA,IAAMuB,cAAc,GAAG,SAAjBA,cAAcA,CAClBC,CAA8D,EAC3D;AACH,QAAA,IAAIA,CAAC,CAACvB,IAAI,CAACH,SAAS,KAAKgB,EAAE,EAAE;AAC3BP,UAAAA,MAAM,CAACkB,mBAAmB,CAAC,SAAS,EAAEF,cAAc,CAAC,CAAA;AACrDP,UAAAA,OAAO,CAACQ,CAAC,CAACvB,IAAI,CAACI,aAAa,CAAC,CAAA;AAC/B,SAAA;OACD,CAAA;AACDE,MAAAA,MAAM,CAACmB,gBAAgB,CAAC,SAAS,EAAEH,cAAc,CAAC,CAAA;MAClDhB,MAAM,CAACoB,WAAW,CAChB;AACE3B,QAAAA,SAAS,EAATA,SAAS;AACTF,QAAAA,SAAS,EAAEgB,EAAAA;OACZ,EACD,EACF,CAAC,CAAA;AACH,KAAA;AACF,GAAC,CAAC,CAAA;AACJ,CAAA;AAEAT,aAAa,CAACuB,aAAa,GAAG,SAASA,aAAaA,GAAG;AACrDF,EAAAA,gBAAgB,CACd,SAAS,EACT,UAACF,CAA4D,EAAK;AAChE,IAAA,IAAAK,OAAA,GAAiCL,CAAC,CAACvB,IAAI;MAA/BD,SAAS,GAAA6B,OAAA,CAAT7B,SAAS;MAAEF,SAAS,GAAA+B,OAAA,CAAT/B,SAAS,CAAA;AAC5B6B,IAAAA,WAAW,CAAC;AACVtB,MAAAA,aAAa,EAAEN,sBAAsB,CAACC,SAAS,CAAC;AAChDF,MAAAA,SAAS,EAATA,SAAAA;AACF,KAAC,CAAC,CAAA;AACJ,GACF,CAAC,CAAA;AACH,CAAC;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@erase2d/fabric",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Fabric.js erase2d bindings",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -34,17 +34,18 @@
34
34
  "optional": false
35
35
  }
36
36
  },
37
- "dependencies": {
38
- "@erase2d/core": "file:../core"
37
+ "devDependencies": {
38
+ "@erase2d/core": "file:../core",
39
+ "@rollup/plugin-node-resolve": "^15.2.3"
39
40
  },
40
- "module": "./dist/index.js",
41
- "types": "./dist/index.d.ts",
41
+ "module": "./dist/fabric/index.js",
42
+ "types": "./dist/fabric/index.d.ts",
42
43
  "exports": {
43
44
  ".": {
44
- "types": "./dist/index.d.ts",
45
- "import": "./dist/index.js",
45
+ "types": "./dist/fabric/index.d.ts",
46
+ "import": "./dist/fabric/index.js",
46
47
  "require": null,
47
- "default": "./dist/index.js"
48
+ "default": "./dist/fabric/index.js"
48
49
  }
49
50
  }
50
51
  }
package/rollup.config.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { babel } from '@rollup/plugin-babel';
2
- import terser from '@rollup/plugin-terser';
2
+ import { nodeResolve } from '@rollup/plugin-node-resolve';
3
3
  import ts from '@rollup/plugin-typescript';
4
4
  import del from 'rollup-plugin-delete';
5
5
 
@@ -16,12 +16,16 @@ export default [
16
16
  preserveModules: true,
17
17
  entryFileNames: '[name].js',
18
18
  sourcemap: true,
19
- plugins: [terser()],
19
+ // plugins: [terser()],
20
20
  },
21
21
  plugins: [
22
22
  del({
23
23
  targets: ['dist/*'],
24
24
  }),
25
+
26
+ // resolve and build `@erase2d/core`
27
+ nodeResolve(),
28
+
25
29
  ts({
26
30
  noForceEmit: true,
27
31
  tsconfig: 'tsconfig.json',
@@ -33,6 +37,6 @@ export default [
33
37
  presets: [['@babel/env'], ['@babel/typescript']],
34
38
  }),
35
39
  ],
36
- external: ['fabric', '@erase2d/core'],
40
+ external: ['fabric'],
37
41
  },
38
42
  ];
package/dist/index.js DELETED
@@ -1,2 +0,0 @@
1
- export{ClippingGroup}from"./src/ClippingGroup.js";export{EraserBrush,eraseCanvasDrawable,eraseObject}from"./src/EraserBrush.js";export{isTransparent}from"./src/isTransparent.js";
2
- //# sourceMappingURL=index.js.map
@@ -1,2 +0,0 @@
1
- import{defineProperty as t,inherits as e,createClass as i,classCallCheck as r,callSuper as a,objectSpread2 as s,assertThisInitialized as n,get as o,getPrototypeOf as l}from"../_virtual/_rollupPluginBabelHelpers.js";import{classRegistry as c,LayoutManager as h,FixedLayout as u,Path as f,Group as p}from"fabric";var g=function(c){function g(e,i){var o;return r(this,g),o=a(this,g,[e,s({layoutManager:new h(new u)},i)]),t(n(o),"blockErasing",!1),o}return e(g,p),i(g,[{key:"drawObject",value:function(t){var e=[],i=[];this._objects.forEach((function(t){return(t instanceof f?e:i).push(t)})),t.save(),t.fillStyle="black",t.fillRect(-this.width/2,-this.height/2,this.width,this.height),t.restore(),!this.blockErasing&&e.forEach((function(e){e.render(t)})),i.forEach((function(e){e.globalCompositeOperation=e.inverted?"destination-out":"source-in",e.render(t)}))}}],[{key:"getDefaults",value:function(){return s(s({},o(l(g),"getDefaults",this).call(this)),{},{originX:"center",originY:"center",left:0,top:0})}}]),g}();t(g,"type","clipping"),c.setClass(g);export{g as ClippingGroup};
2
- //# sourceMappingURL=ClippingGroup.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ClippingGroup.js","sources":["../../src/ClippingGroup.ts"],"sourcesContent":["import {\n Group,\n LayoutManager,\n FixedLayout,\n Path,\n FabricObject,\n GroupProps,\n classRegistry,\n} from 'fabric';\n\nexport class ClippingGroup extends Group {\n static type = 'clipping';\n\n static getDefaults(): Record<string, any> {\n return {\n ...super.getDefaults(),\n originX: 'center',\n originY: 'center',\n left: 0,\n top: 0,\n };\n }\n\n private blockErasing = false;\n\n constructor(objects: FabricObject[], options: Partial<GroupProps>) {\n super(objects, {\n layoutManager: new LayoutManager(new FixedLayout()),\n ...options,\n });\n }\n\n drawObject(ctx: CanvasRenderingContext2D) {\n const paths: Path[] = [];\n const objects: FabricObject[] = [];\n this._objects.forEach((object) =>\n (object instanceof Path ? paths : objects).push(object)\n );\n\n ctx.save();\n ctx.fillStyle = 'black';\n ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);\n ctx.restore();\n\n !this.blockErasing &&\n paths.forEach((path) => {\n path.render(ctx);\n });\n\n objects.forEach((object) => {\n object.globalCompositeOperation = object.inverted\n ? 'destination-out'\n : 'source-in';\n object.render(ctx);\n });\n }\n}\n\nclassRegistry.setClass(ClippingGroup);\n"],"names":["ClippingGroup","_Group","objects","options","_this","_classCallCheck","_callSuper","this","_objectSpread","layoutManager","LayoutManager","FixedLayout","_defineProperty","_assertThisInitialized","_inherits","Group","_createClass","key","value","ctx","paths","_objects","forEach","object","Path","push","save","fillStyle","fillRect","width","height","restore","blockErasing","path","render","globalCompositeOperation","inverted","_get","_getPrototypeOf","call","originX","originY","left","top","classRegistry","setClass"],"mappings":"uTAUaA,IAAAA,WAAaC,GAexB,SAAAD,EAAYE,EAAyBC,GAA8B,IAAAC,EAFvC,OAEuCC,OAAAL,GACjEI,EAAAE,EAAAC,KAAAP,EAAME,CAAAA,EAAOM,EAAA,CACXC,cAAe,IAAIC,EAAc,IAAIC,IAClCR,KACFS,EAAAC,EAAAT,mBANkB,GAAKA,CAO5B,CATC,OAXuBU,EAAAd,EAASe,GAoBhCC,EAAAhB,EAAA,CAAA,CAAAiB,IAAA,aAAAC,MAED,SAAWC,GACT,IAAMC,EAAgB,GAChBlB,EAA0B,GAChCK,KAAKc,SAASC,SAAQ,SAACC,GAAM,OAC1BA,aAAkBC,EAAOJ,EAAQlB,GAASuB,KAAKF,EAAO,IAGzDJ,EAAIO,OACJP,EAAIQ,UAAY,QAChBR,EAAIS,UAAUrB,KAAKsB,MAAQ,GAAItB,KAAKuB,OAAS,EAAGvB,KAAKsB,MAAOtB,KAAKuB,QACjEX,EAAIY,WAEHxB,KAAKyB,cACJZ,EAAME,SAAQ,SAACW,GACbA,EAAKC,OAAOf,EACd,IAEFjB,EAAQoB,SAAQ,SAACC,GACfA,EAAOY,yBAA2BZ,EAAOa,SACrC,kBACA,YACJb,EAAOW,OAAOf,EAChB,GACF,IAAC,CAAA,CAAAF,IAAA,cAAAC,MA1CD,WACE,OAAAV,EAAAA,EAAA6B,CAAAA,EAAAA,EAAAC,EAAAtC,GAAA,cAAAO,MAAAgC,KAAAhC,OAAA,CAAA,EAAA,CAEEiC,QAAS,SACTC,QAAS,SACTC,KAAM,EACNC,IAAK,GAET,KAAC3C,CAAA,IAmCFY,EA9CYZ,EAAa,OACV,YA+ChB4C,EAAcC,SAAS7C"}
@@ -1,2 +0,0 @@
1
- import{asyncToGenerator as t,inherits as e,createClass as n,regeneratorRuntime as r,classCallCheck as a,callSuper as i,defineProperty as s,assertThisInitialized as o,get as c,getPrototypeOf as u,toConsumableArray as l,slicedToArray as h}from"../_virtual/_rollupPluginBabelHelpers.js";import{erase as v}from"@erase2d/core";import*as p from"fabric";import{Group as f}from"fabric";import{ClippingGroup as d}from"./ClippingGroup.js";import{draw as m}from"./ErasingEffect.js";function g(t,e){return t.flatMap((function(t){return t.erasable&&t.intersectsWithObject(e)?t instanceof f&&"deep"===t.erasable?g(t.getObjects(),e):[t]:[]}))}var y=function(t){var e=t.clipPath;if(e instanceof d)return e;var n=t._limitCacheSize(t._getCacheCanvasDimensions()),r=n.width,a=n.height,i=new d([],{width:r,height:a});if(e){var s=e.translateToOriginPoint(new p.Point,e.originX,e.originY),o=s.x,c=s.y;e.originX=e.originY="center",p.util.sendObjectToPlane(e,void 0,p.util.createTranslateMatrix(o,c)),i.add(e)}return t.clipPath=i};function w(t,e){var n=y(t);n.add(e),n.set("dirty",!0),t.set("dirty",!0)}function x(t,e){return E.apply(this,arguments)}function E(){return(E=t(r().mark((function t(e,n){var a;return r().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,n.clone();case 2:return a=t.sent,p.util.sendObjectToPlane(a,void 0,e.calcTransformMatrix()),w(e,a),t.abrupt("return",a);case 6:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function b(t,e,n){return C.apply(this,arguments)}function C(){return(C=t(r().mark((function t(e,n,a){var i,s;return r().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,a.clone();case 2:return i=t.sent,s=n&&e.translateToOriginPoint(new p.Point,e.originX,e.originY),p.util.sendObjectToPlane(i,void 0,s?p.util.multiplyTransformMatrixArray([[1,0,0,1,s.x,s.y],n,[1,0,0,1,-s.x,-s.y],e.calcTransformMatrix()]):e.calcTransformMatrix()),w(e,i),t.abrupt("return",i);case 7:case"end":return t.stop()}}),t)})))).apply(this,arguments)}var k=function(f){function d(t){var e;a(this,d),e=i(this,d,[t]),s(o(e),"inverted",!1),s(o(e),"active",!1);var n=document.createElement("canvas"),r=n.getContext("2d");if(!r)throw new Error("Failed to get context");return function(t,e,n){var r=n.width,a=n.height,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:1;t.width=r,t.height=a,i>1&&(t.setAttribute("width",(r*i).toString()),t.setAttribute("height",(a*i).toString()),e.scale(i,i))}(n,r,t,e.canvas.getRetinaScaling()),e.effectContext=r,e.eventEmitter=new EventTarget,e}var y;return e(d,f),n(d,[{key:"on",value:function(t,e,n){var r=this;return this.eventEmitter.addEventListener(t,e,n),function(){return r.eventEmitter.removeEventListener(t,e,n)}}},{key:"drawEffect",value:function(){m(this.effectContext,{opacity:new p.Color(this.color).getAlpha(),inverted:this.inverted},{canvas:this.canvas})}},{key:"_setBrushStyles",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.canvas.contextTop;c(u(d.prototype),"_setBrushStyles",this).call(this,t),t.strokeStyle="black"}},{key:"needsFullRender",value:function(){return!0}},{key:"_render",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.canvas.getTopContext();c(u(d.prototype),"_render",this).call(this,t),v(this.canvas.getContext(),t,this.effectContext)}},{key:"onMouseDown",value:function(t,e){var n=this;this.eventEmitter.dispatchEvent(new CustomEvent("start",{detail:e,cancelable:!0}))&&(this.active=!0,this.eventEmitter.dispatchEvent(new CustomEvent("redraw",{detail:{type:"start"},cancelable:!0}))&&this.drawEffect(),this._disposer=this.canvas.on("after:render",(function(t){t.ctx===n.canvas.getContext()&&(n.eventEmitter.dispatchEvent(new CustomEvent("redraw",{detail:{type:"render"},cancelable:!0}))&&n.drawEffect(),n._render())})),c(u(d.prototype),"onMouseDown",this).call(this,t,e))}},{key:"onMouseMove",value:function(t,e){this.active&&this.eventEmitter.dispatchEvent(new CustomEvent("move",{detail:e,cancelable:!0}))&&c(u(d.prototype),"onMouseMove",this).call(this,t,e)}},{key:"onMouseUp",value:function(t){var e;return this.active&&c(u(d.prototype),"onMouseUp",this).call(this,t),this.active=!1,null===(e=this._disposer)||void 0===e||e.call(this),delete this._disposer,!1}},{key:"convertPointsToSVGPath",value:function(t){return c(u(d.prototype),"convertPointsToSVGPath",this).call(this,this.decimate?this.decimatePoints(t,this.decimate):t)}},{key:"createPath",value:function(t){var e=c(u(d.prototype),"createPath",this).call(this,t);return e.set(this.inverted?{globalCompositeOperation:"source-over",stroke:"white"}:{globalCompositeOperation:"destination-out",stroke:"black",opacity:new p.Color(this.color).getAlpha()}),e}},{key:"commit",value:(y=t(r().mark((function e(n){var a,i;return r().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return a=n.path,i=n.targets,e.t0=Map,e.next=4,Promise.all([].concat(l(i.map(function(){var e=t(r().mark((function t(e){return r().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.t0=e,t.next=3,x(e,a);case 3:return t.t1=t.sent,t.abrupt("return",[t.t0,t.t1]);case 5:case"end":return t.stop()}}),t)})));return function(t){return e.apply(this,arguments)}}())),l([[this.canvas.backgroundImage,this.canvas.backgroundVpt?void 0:this.canvas.viewportTransform],[this.canvas.overlayImage,this.canvas.overlayVpt?void 0:this.canvas.viewportTransform]].filter((function(t){return h(t,1)[0]})).map(function(){var e=t(r().mark((function t(e){var n,i,s;return r().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=h(e,2),i=n[0],s=n[1],t.t0=i,t.next=4,b(i,s,a);case 4:return t.t1=t.sent,t.abrupt("return",[t.t0,t.t1]);case 6:case"end":return t.stop()}}),t)})));return function(t){return e.apply(this,arguments)}}()))));case 4:e.t1=e.sent,new e.t0(e.t1);case 6:case"end":return e.stop()}}),e,this)}))),function(t){return y.apply(this,arguments)})},{key:"_finalizeAndAddPath",value:function(){var t=this._points;if(t.length<2)this.eventEmitter.dispatchEvent(new CustomEvent("cancel",{cancelable:!1}));else{var e=this.createPath(this.convertPointsToSVGPath(t)),n=g(this.canvas.getObjects(),e);this.eventEmitter.dispatchEvent(new CustomEvent("end",{detail:{path:e,targets:n},cancelable:!0}))&&this.commit({path:e,targets:n}),this.canvas.clearContext(this.canvas.contextTop),this.canvas.requestRenderAll(),this._resetShadow()}}},{key:"dispose",value:function(){var t=this.effectContext.canvas;t.width=t.height=0}}]),d}(p.PencilBrush);export{k as EraserBrush,w as commitErasing,b as eraseCanvasDrawable,x as eraseObject};
2
- //# sourceMappingURL=EraserBrush.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"EraserBrush.js","sources":["../../src/EraserBrush.ts"],"sourcesContent":["import { erase } from '@erase2d/core';\nimport * as fabric from 'fabric';\nimport { FabricObject, Group, Path } from 'fabric';\nimport { ClippingGroup } from './ClippingGroup';\nimport { draw } from './ErasingEffect';\n\nexport type EventDetailMap = {\n start: fabric.TEvent<fabric.TPointerEvent>;\n move: fabric.TEvent<fabric.TPointerEvent>;\n end: {\n path: fabric.Path;\n targets: fabric.FabricObject[];\n };\n redraw: { type: 'start' | 'render' };\n cancel: never;\n};\n\nexport type ErasingEventType = keyof EventDetailMap;\n\nexport type ErasingEvent<T extends ErasingEventType> = CustomEvent<\n EventDetailMap[T]\n>;\n\nfunction walk(objects: FabricObject[], path: Path): FabricObject[] {\n return objects.flatMap((object) => {\n if (!object.erasable || !object.intersectsWithObject(path)) {\n return [];\n } else if (object instanceof Group && object.erasable === 'deep') {\n return walk(object.getObjects(), path);\n } else {\n return [object];\n }\n });\n}\n\nconst assertClippingGroup = (object: fabric.FabricObject) => {\n const curr = object.clipPath;\n\n if (curr instanceof ClippingGroup) {\n return curr;\n }\n\n // In order to support objects with stroke width, stroke uniform, shadow etc.\n // we use the actual drawn size\n const { width, height } = object._limitCacheSize(\n object._getCacheCanvasDimensions()\n );\n\n const next = new ClippingGroup([], {\n width,\n height,\n });\n\n if (curr) {\n const { x, y } = curr.translateToOriginPoint(\n new fabric.Point(),\n curr.originX,\n curr.originY\n );\n curr.originX = curr.originY = 'center';\n fabric.util.sendObjectToPlane(\n curr,\n undefined,\n fabric.util.createTranslateMatrix(x, y)\n );\n next.add(curr as FabricObject);\n }\n\n return (object.clipPath = next);\n};\n\nexport function commitErasing(\n object: fabric.FabricObject,\n sourceInObjectPlane: fabric.Path\n) {\n const clipPath = assertClippingGroup(object);\n clipPath.add(sourceInObjectPlane);\n clipPath.set('dirty', true);\n object.set('dirty', true);\n}\n\nexport async function eraseObject(\n object: fabric.FabricObject,\n source: fabric.Path\n) {\n const clone = await source.clone();\n fabric.util.sendObjectToPlane(clone, undefined, object.calcTransformMatrix());\n commitErasing(object, clone);\n return clone;\n}\n\nexport async function eraseCanvasDrawable(\n object: fabric.FabricObject,\n vpt: fabric.TMat2D | undefined,\n source: fabric.Path\n) {\n const clone = await source.clone();\n const d =\n vpt &&\n object.translateToOriginPoint(\n new fabric.Point(),\n object.originX,\n object.originY\n );\n fabric.util.sendObjectToPlane(\n clone,\n undefined,\n d\n ? fabric.util.multiplyTransformMatrixArray([\n [1, 0, 0, 1, d.x, d.y],\n // apply vpt from center of drawable\n vpt,\n [1, 0, 0, 1, -d.x, -d.y],\n object.calcTransformMatrix(),\n ])\n : object.calcTransformMatrix()\n );\n commitErasing(object, clone);\n return clone;\n}\n\nconst setCanvasDimensions = (\n el: HTMLCanvasElement,\n ctx: CanvasRenderingContext2D,\n { width, height }: fabric.TSize,\n retinaScaling = 1\n) => {\n el.width = width;\n el.height = height;\n if (retinaScaling > 1) {\n el.setAttribute('width', (width * retinaScaling).toString());\n el.setAttribute('height', (height * retinaScaling).toString());\n ctx.scale(retinaScaling, retinaScaling);\n }\n};\n\n/**\n * Supports **selective** erasing: only erasable objects are affected by the eraser brush.\n *\n * Supports **{@link inverted}** erasing: the brush can \"undo\" erasing.\n *\n * Supports **alpha** erasing: setting the alpha channel of the `color` property controls the eraser intensity.\n *\n * In order to support selective erasing, the brush clips the entire canvas and\n * masks all non-erasable objects over the erased path, see {@link draw}.\n *\n * If **{@link inverted}** draws all objects, erasable objects without their eraser, over the erased path.\n * This achieves the desired effect of seeming to erase or undo erasing on erasable objects only.\n *\n * After erasing is done the `end` event {@link ErasingEndEvent} is fired, after which erasing will be committed to the tree.\n * @example\n * canvas = new Canvas();\n * const eraser = new EraserBrush(canvas);\n * canvas.freeDrawingBrush = eraser;\n * canvas.isDrawingMode = true;\n * eraser.on('start', (e) => {\n * console.log('started erasing');\n * // prevent erasing\n * e.preventDefault();\n * });\n * eraser.on('end', (e) => {\n * const { targets: erasedTargets, path } = e.detail;\n * e.preventDefault(); // prevent erasing being committed to the tree\n * eraser.commit({ targets: erasedTargets, path }); // commit manually since default was prevented\n * });\n *\n * In case of performance issues trace {@link drawEffect} calls and consider preventing it from executing\n * @example\n * const eraser = new EraserBrush(canvas);\n * eraser.on('redraw', (e) => {\n * // prevent effect redraw on pointer down (e.g. useful if canvas didn't change)\n * e.detail.type === 'start' && e.preventDefault());\n * // prevent effect redraw after canvas has rendered (effect will become stale)\n * e.detail.type === 'render' && e.preventDefault());\n * });\n */\nexport class EraserBrush extends fabric.PencilBrush {\n /**\n * When set to `true` the brush will create a visual effect of undoing erasing\n */\n inverted = false;\n\n effectContext: CanvasRenderingContext2D;\n\n private eventEmitter: EventTarget;\n private active = false;\n private _disposer?: VoidFunction;\n\n constructor(canvas: fabric.Canvas) {\n super(canvas);\n const el = document.createElement('canvas');\n const ctx = el.getContext('2d');\n if (!ctx) {\n throw new Error('Failed to get context');\n }\n setCanvasDimensions(el, ctx, canvas, this.canvas.getRetinaScaling());\n this.effectContext = ctx;\n this.eventEmitter = new EventTarget();\n }\n\n /**\n * @returns disposer make sure to call it to avoid memory leaks\n */\n on<T extends ErasingEventType>(\n type: T,\n cb: (evt: ErasingEvent<T>) => any,\n options?: boolean | AddEventListenerOptions\n ) {\n this.eventEmitter.addEventListener(type, cb as EventListener, options);\n return () =>\n this.eventEmitter.removeEventListener(type, cb as EventListener, options);\n }\n\n drawEffect() {\n draw(\n this.effectContext,\n {\n opacity: new fabric.Color(this.color).getAlpha(),\n inverted: this.inverted,\n },\n { canvas: this.canvas }\n );\n }\n\n /**\n * @override\n */\n _setBrushStyles(ctx: CanvasRenderingContext2D = this.canvas.contextTop) {\n super._setBrushStyles(ctx);\n ctx.strokeStyle = 'black';\n }\n\n /**\n * @override strictly speaking the eraser needs a full render only if it has opacity set.\n * However since {@link PencilBrush} is designed for subclassing that is what we have to work with.\n */\n needsFullRender(): boolean {\n return true;\n }\n\n /**\n * @override erase\n */\n _render(ctx: CanvasRenderingContext2D = this.canvas.getTopContext()): void {\n super._render(ctx);\n erase(this.canvas.getContext(), ctx, this.effectContext);\n }\n\n /**\n * @override {@link drawEffect}\n */\n onMouseDown(\n pointer: fabric.Point,\n context: fabric.TEvent<fabric.TPointerEvent>\n ): void {\n if (\n !this.eventEmitter.dispatchEvent(\n new CustomEvent('start', { detail: context, cancelable: true })\n )\n ) {\n return;\n }\n\n this.active = true;\n\n this.eventEmitter.dispatchEvent(\n new CustomEvent('redraw', {\n detail: { type: 'start' },\n cancelable: true,\n })\n ) && this.drawEffect();\n\n // consider a different approach\n this._disposer = this.canvas.on('after:render', ({ ctx }) => {\n if (ctx !== this.canvas.getContext()) {\n return;\n }\n this.eventEmitter.dispatchEvent(\n new CustomEvent('redraw', {\n detail: { type: 'render' },\n cancelable: true,\n })\n ) && this.drawEffect();\n this._render();\n });\n\n super.onMouseDown(pointer, context);\n }\n\n /**\n * @override run if active\n */\n onMouseMove(\n pointer: fabric.Point,\n context: fabric.TEvent<fabric.TPointerEvent>\n ): void {\n this.active &&\n this.eventEmitter.dispatchEvent(\n new CustomEvent('move', { detail: context, cancelable: true })\n ) &&\n super.onMouseMove(pointer, context);\n }\n\n /**\n * @override run if active, dispose of {@link drawEffect} listener\n */\n onMouseUp(context: fabric.TEvent<fabric.TPointerEvent>): boolean {\n this.active && super.onMouseUp(context);\n this.active = false;\n this._disposer?.();\n delete this._disposer;\n return false;\n }\n\n /**\n * @override {@link fabric.PencilBrush} logic\n */\n convertPointsToSVGPath(points: fabric.Point[]): fabric.util.TSimplePathData {\n return super.convertPointsToSVGPath(\n this.decimate ? this.decimatePoints(points, this.decimate) : points\n );\n }\n\n /**\n * @override\n */\n createPath(pathData: fabric.util.TSimplePathData) {\n const path = super.createPath(pathData);\n path.set(\n this.inverted\n ? {\n globalCompositeOperation: 'source-over',\n stroke: 'white',\n }\n : {\n globalCompositeOperation: 'destination-out',\n stroke: 'black',\n opacity: new fabric.Color(this.color).getAlpha(),\n }\n );\n return path;\n }\n\n async commit({ path, targets }: EventDetailMap['end']) {\n new Map(\n await Promise.all([\n ...targets.map(async (object) => {\n return [object, await eraseObject(object, path)] as const;\n }),\n ...(\n [\n [\n this.canvas.backgroundImage,\n !this.canvas.backgroundVpt\n ? this.canvas.viewportTransform\n : undefined,\n ],\n [\n this.canvas.overlayImage,\n !this.canvas.overlayVpt\n ? this.canvas.viewportTransform\n : undefined,\n ],\n ] as const\n )\n .filter(([object]) => object)\n .map(async ([object, vptFlag]) => {\n return [\n object,\n await eraseCanvasDrawable(object as FabricObject, vptFlag, path),\n ] as const;\n }),\n ])\n );\n }\n\n /**\n * @override handle events\n */\n _finalizeAndAddPath(): void {\n const points = this['_points'];\n\n if (points.length < 2) {\n this.eventEmitter.dispatchEvent(\n new CustomEvent('cancel', {\n cancelable: false,\n })\n );\n return;\n }\n\n const path = this.createPath(this.convertPointsToSVGPath(points));\n const targets = walk(this.canvas.getObjects(), path);\n\n this.eventEmitter.dispatchEvent(\n new CustomEvent('end', {\n detail: {\n path,\n targets,\n },\n cancelable: true,\n })\n ) && this.commit({ path, targets });\n\n this.canvas.clearContext(this.canvas.contextTop);\n this.canvas.requestRenderAll();\n\n this._resetShadow();\n }\n\n dispose() {\n const { canvas } = this.effectContext;\n // prompt GC\n canvas.width = canvas.height = 0;\n // release ref?\n // delete this.effectContext\n }\n}\n"],"names":["walk","objects","path","flatMap","object","erasable","intersectsWithObject","Group","getObjects","assertClippingGroup","curr","clipPath","ClippingGroup","_object$_limitCacheSi","_limitCacheSize","_getCacheCanvasDimensions","width","height","next","_curr$translateToOrig","translateToOriginPoint","fabric","Point","originX","originY","x","y","util","sendObjectToPlane","undefined","createTranslateMatrix","add","commitErasing","sourceInObjectPlane","set","eraseObject","_x","_x2","_eraseObject","apply","this","arguments","_asyncToGenerator","_regeneratorRuntime","mark","_callee4","source","clone","wrap","_context4","prev","sent","calcTransformMatrix","abrupt","stop","eraseCanvasDrawable","_x3","_x4","_x5","_eraseCanvasDrawable","_callee5","vpt","d","_context5","multiplyTransformMatrixArray","EraserBrush","_fabric$PencilBrush","canvas","_this","_classCallCheck","_callSuper","_defineProperty","_assertThisInitialized","el","document","createElement","ctx","getContext","Error","_ref","retinaScaling","length","setAttribute","toString","scale","setCanvasDimensions","getRetinaScaling","effectContext","eventEmitter","EventTarget","_commit","_inherits","_createClass","key","value","type","cb","options","_this2","addEventListener","removeEventListener","draw","opacity","Color","color","getAlpha","inverted","contextTop","_get","_getPrototypeOf","prototype","call","strokeStyle","getTopContext","erase","pointer","context","_this3","dispatchEvent","CustomEvent","detail","cancelable","active","drawEffect","_disposer","on","_ref2","_render","_this$_disposer","points","decimate","decimatePoints","pathData","globalCompositeOperation","stroke","_callee3","_ref3","targets","_context3","t0","Map","Promise","all","concat","_toConsumableArray","map","_ref4","_callee","_context","t1","_x7","backgroundImage","backgroundVpt","viewportTransform","overlayImage","overlayVpt","filter","_ref5","_slicedToArray","_ref8","_callee2","_ref7","_ref9","vptFlag","_context2","_x8","_x6","createPath","convertPointsToSVGPath","commit","clearContext","requestRenderAll","_resetShadow","PencilBrush"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{toConsumableArray as t}from"../_virtual/_rollupPluginBabelHelpers.js";import{Group as r}from"fabric";import{ClippingGroup as a}from"./ClippingGroup.js";function e(t){return t.flatMap((function(t){return!t.erasable||t.isNotVisible()?[]:t instanceof r&&"deep"===t.erasable?e(t.getObjects()):[t]}))}function o(r,o,i){var n=o.inverted,c=o.opacity,l=i.canvas,p=i.objects,s=void 0===p?l._objectsToRender||l._objects:p,u=i.background,d=void 0===u?l.backgroundImage:u,f=i.overlay,b=void 0===f?l.overlayImage:f,h=1-c,m=e([].concat(t(s),t([d,b].filter((function(t){return!!t}))))).map((function(t){if(!n){var r,e=t.opacity;return t.opacity*=h,null===(r=t.parent)||void 0===r||r.set("dirty",!0),{object:t,opacity:e}}if(t.clipPath instanceof a)return t.clipPath.blockErasing=!0,t.clipPath.set("dirty",!0),t.set("dirty",!0),{object:t,clipPath:t.clipPath}}));!function(r,a,e){a.clearContext(r),r.imageSmoothingEnabled=a.imageSmoothingEnabled,r.imageSmoothingQuality="high",r.patternQuality="best",a._renderBackground(r),r.save(),r.transform.apply(r,t(a.viewportTransform)),e.forEach((function(t){return t.render(r)})),r.restore();var o=a.clipPath;o&&(o._set("canvas",a),o.shouldCache(),o._transformDone=!0,o.renderCache({forClipping:!0}),a.drawClipPathOnCanvas(r,o)),a._renderOverlay(r)}(r,l,s),m.forEach((function(t){var r;t&&(t.opacity?(t.object.opacity=c,null===(r=t.object.parent)||void 0===r||r.set("dirty",!0)):t.clipPath&&(t.clipPath.blockErasing=!1,t.clipPath.set("dirty",!0),t.object.set("dirty",!0)))}))}export{o as draw};
2
- //# sourceMappingURL=ErasingEffect.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ErasingEffect.js","sources":["../../src/ErasingEffect.ts"],"sourcesContent":["import { Canvas, FabricObject, Group } from 'fabric';\nimport { ClippingGroup } from './ClippingGroup';\n\nfunction walk(objects: FabricObject[]): FabricObject[] {\n return objects.flatMap((object) => {\n if (!object.erasable || object.isNotVisible()) {\n return [];\n } else if (object instanceof Group && object.erasable === 'deep') {\n return walk(object.getObjects());\n } else {\n return [object];\n }\n });\n}\n\nfunction drawCanvas(\n ctx: CanvasRenderingContext2D,\n canvas: Canvas,\n objects: FabricObject[]\n) {\n canvas.clearContext(ctx);\n\n ctx.imageSmoothingEnabled = canvas.imageSmoothingEnabled;\n ctx.imageSmoothingQuality = 'high';\n // @ts-expect-error node-canvas stuff\n ctx.patternQuality = 'best';\n\n canvas._renderBackground(ctx);\n\n ctx.save();\n ctx.transform(...canvas.viewportTransform);\n objects.forEach((object) => object.render(ctx));\n ctx.restore();\n\n const clipPath = canvas.clipPath;\n if (clipPath) {\n // fabric crap\n clipPath._set('canvas', canvas);\n clipPath.shouldCache();\n clipPath._transformDone = true;\n clipPath.renderCache({ forClipping: true });\n canvas.drawClipPathOnCanvas(ctx, clipPath as any);\n }\n\n canvas._renderOverlay(ctx);\n}\n\n/**\n * Prepare the pattern for the erasing brush\n * This pattern will be drawn on the top context after clipping the main context,\n * achieving a visual effect of erasing only erasable objects.\n *\n * This is designed to support erasing a collection with both erasable and non-erasable objects while maintaining object stacking.\\\n * Iterates over collections to allow nested selective erasing.\\\n * Prepares objects before rendering the pattern brush.\\\n * If brush is **NOT** inverted render all non-erasable objects.\\\n * If brush is inverted render all objects, erasable objects without their eraser.\n * This will render the erased parts as if they were not erased in the first place, achieving an undo effect.\n *\n * Caveat:\n * Does not support erasing effects of shadows\n *\n */\nexport function draw(\n ctx: CanvasRenderingContext2D,\n { inverted, opacity }: { inverted: boolean; opacity: number },\n {\n canvas,\n objects = canvas._objectsToRender || canvas._objects,\n background = canvas.backgroundImage,\n overlay = canvas.overlayImage,\n }: {\n canvas: Canvas;\n objects?: FabricObject[];\n background?: FabricObject;\n overlay?: FabricObject;\n }\n) {\n // prepare tree\n const alpha = 1 - opacity;\n const restore = walk([\n ...objects,\n ...([background, overlay] as FabricObject[]).filter((d) => !!d),\n ]).map((object) => {\n if (!inverted) {\n // render only non-erasable objects\n const opacity = object.opacity;\n object.opacity *= alpha;\n object.parent?.set('dirty', true);\n return { object, opacity };\n } else if (object.clipPath instanceof ClippingGroup) {\n // render all objects without eraser\n object.clipPath['blockErasing'] = true;\n object.clipPath.set('dirty', true);\n object.set('dirty', true);\n return { object, clipPath: object.clipPath };\n }\n });\n\n // draw\n drawCanvas(ctx, canvas, objects);\n\n // restore\n restore.forEach((entry) => {\n if (!entry) {\n return;\n }\n if (entry.opacity) {\n entry.object.opacity = opacity;\n entry.object.parent?.set('dirty', true);\n } else if (entry.clipPath) {\n entry.clipPath['blockErasing'] = false;\n entry.clipPath.set('dirty', true);\n entry.object.set('dirty', true);\n }\n });\n}\n"],"names":["walk","objects","flatMap","object","erasable","isNotVisible","Group","getObjects","draw","ctx","_ref","_ref2","inverted","opacity","canvas","_ref2$objects","_objectsToRender","_objects","_ref2$background","background","backgroundImage","_ref2$overlay","overlay","overlayImage","alpha","restore","concat","_toConsumableArray","filter","d","map","_object$parent","parent","set","clipPath","ClippingGroup","clearContext","imageSmoothingEnabled","imageSmoothingQuality","patternQuality","_renderBackground","save","transform","apply","viewportTransform","forEach","render","_set","shouldCache","_transformDone","renderCache","forClipping","drawClipPathOnCanvas","_renderOverlay","drawCanvas","entry","_entry$object$parent"],"mappings":"+JAGA,SAASA,EAAKC,GACZ,OAAOA,EAAQC,SAAQ,SAACC,GACtB,OAAKA,EAAOC,UAAYD,EAAOE,eACtB,GACEF,aAAkBG,GAA6B,SAApBH,EAAOC,SACpCJ,EAAKG,EAAOI,cAEZ,CAACJ,EAEZ,GACF,CAkDO,SAASK,EACdC,EAA6BC,EAAAC,GAa7B,IAZEC,EAAQF,EAARE,SAAUC,EAAOH,EAAPG,QAEVC,EAAMH,EAANG,OAAMC,EAAAJ,EACNV,QAAAA,OAAO,IAAAc,EAAGD,EAAOE,kBAAoBF,EAAOG,SAAQF,EAAAG,EAAAP,EACpDQ,WAAAA,OAAU,IAAAD,EAAGJ,EAAOM,gBAAeF,EAAAG,EAAAV,EACnCW,QAAAA,OAAO,IAAAD,EAAGP,EAAOS,aAAYF,EASzBG,EAAQ,EAAIX,EACZY,EAAUzB,EAAI,GAAA0B,OAAAC,EACf1B,GAAO0B,EACN,CAACR,EAAYG,GAA4BM,QAAO,SAACC,GAAC,QAAOA,CAAC,OAC7DC,KAAI,SAAC3B,GACN,IAAKS,EAAU,CAAA,IAAAmB,EAEPlB,EAAUV,EAAOU,QAGvB,OAFAV,EAAOU,SAAWW,EACLO,QAAbA,EAAA5B,EAAO6B,cAAPD,IAAaA,GAAbA,EAAeE,IAAI,SAAS,GACrB,CAAE9B,OAAAA,EAAQU,QAAAA,EACnB,CAAO,GAAIV,EAAO+B,oBAAoBC,EAKpC,OAHAhC,EAAO+B,SAAuB,cAAI,EAClC/B,EAAO+B,SAASD,IAAI,SAAS,GAC7B9B,EAAO8B,IAAI,SAAS,GACb,CAAE9B,OAAAA,EAAQ+B,SAAU/B,EAAO+B,SAEtC,KAlFF,SACEzB,EACAK,EACAb,GAEAa,EAAOsB,aAAa3B,GAEpBA,EAAI4B,sBAAwBvB,EAAOuB,sBACnC5B,EAAI6B,sBAAwB,OAE5B7B,EAAI8B,eAAiB,OAErBzB,EAAO0B,kBAAkB/B,GAEzBA,EAAIgC,OACJhC,EAAIiC,UAASC,MAAblC,EAAGkB,EAAcb,EAAO8B,oBACxB3C,EAAQ4C,SAAQ,SAAC1C,GAAM,OAAKA,EAAO2C,OAAOrC,MAC1CA,EAAIgB,UAEJ,IAAMS,EAAWpB,EAAOoB,SACpBA,IAEFA,EAASa,KAAK,SAAUjC,GACxBoB,EAASc,cACTd,EAASe,gBAAiB,EAC1Bf,EAASgB,YAAY,CAAEC,aAAa,IACpCrC,EAAOsC,qBAAqB3C,EAAKyB,IAGnCpB,EAAOuC,eAAe5C,EACxB,CAuDE6C,CAAW7C,EAAKK,EAAQb,GAGxBwB,EAAQoB,SAAQ,SAACU,GAII,IAAAC,EAHdD,IAGDA,EAAM1C,SACR0C,EAAMpD,OAAOU,QAAUA,EACJ,QAAnB2C,EAAAD,EAAMpD,OAAO6B,cAAM,IAAAwB,GAAnBA,EAAqBvB,IAAI,SAAS,IACzBsB,EAAMrB,WACfqB,EAAMrB,SAAuB,cAAI,EACjCqB,EAAMrB,SAASD,IAAI,SAAS,GAC5BsB,EAAMpD,OAAO8B,IAAI,SAAS,IAE9B,GACF"}
@@ -1,2 +0,0 @@
1
- var e=-1,a=function(e){return e.data.every((function(e,a){return a%4!=3||0===e}))};function t(t,n){var s=t.toCanvasElement({enableRetinaScaling:!1,viewportTransform:!1,withoutTransform:!0,withoutShadow:!0}),r=++e;return new Promise((function(e,t){var i,o=null===(i=s.getContext("2d"))||void 0===i?void 0:i.getImageData(0,0,s.width,s.height);if(o)if(n){n.addEventListener("message",(function a(t){t.data.messageID===r&&(n.removeEventListener("message",a),e(t.data.isTransparent))})),n.postMessage({imageData:o,messageID:r},[])}else e(a(o));else t()}))}t.installWorker=function(){addEventListener("message",(function(e){var t=e.data,n=t.imageData,s=t.messageID;postMessage({isTransparent:a(n),messageID:s})}))};export{t as isTransparent};
2
- //# sourceMappingURL=isTransparent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"isTransparent.js","sources":["../../src/isTransparent.ts"],"sourcesContent":["import { type FabricObject } from 'fabric';\n\nlet messageID = -1;\n\nconst isImageDataTransparent = (imageData: ImageData) =>\n imageData.data.every((x, i) => i % 4 !== 3 || x === 0);\n\nfunction isTransparent(object: FabricObject, worker?: Worker) {\n // should also move to offscreen\n const canvas = object.toCanvasElement({\n // multiplier: 0.1,\n enableRetinaScaling: false,\n viewportTransform: false,\n withoutTransform: true,\n withoutShadow: true,\n });\n\n const id = ++messageID;\n return new Promise<boolean>((resolve, reject) => {\n const imageData = canvas\n .getContext('2d')\n ?.getImageData(0, 0, canvas.width, canvas.height);\n\n if (!imageData) {\n reject();\n } else if (!worker) {\n resolve(isImageDataTransparent(imageData));\n } else {\n const messageHandler = (\n e: MessageEvent<{ messageID: number; isTransparent: boolean }>\n ) => {\n if (e.data.messageID === id) {\n worker.removeEventListener('message', messageHandler);\n resolve(e.data.isTransparent);\n }\n };\n worker.addEventListener('message', messageHandler);\n worker.postMessage(\n {\n imageData,\n messageID: id,\n },\n []\n );\n }\n });\n}\n\nisTransparent.installWorker = function installWorker() {\n addEventListener(\n 'message',\n (e: MessageEvent<{ imageData: ImageData; messageID: number }>) => {\n const { imageData, messageID } = e.data;\n postMessage({\n isTransparent: isImageDataTransparent(imageData),\n messageID,\n });\n }\n );\n};\n\nexport { isTransparent };\n"],"names":["messageID","isImageDataTransparent","imageData","data","every","x","i","isTransparent","object","worker","canvas","toCanvasElement","enableRetinaScaling","viewportTransform","withoutTransform","withoutShadow","id","Promise","resolve","reject","_canvas$getContext","getContext","getImageData","width","height","addEventListener","messageHandler","e","removeEventListener","postMessage","installWorker","_e$data"],"mappings":"AAEA,IAAIA,GAAa,EAEXC,EAAyB,SAACC,GAAoB,OAClDA,EAAUC,KAAKC,OAAM,SAACC,EAAGC,GAAC,OAAKA,EAAI,GAAM,GAAW,IAAND,IAAQ,EAExD,SAASE,EAAcC,EAAsBC,GAE3C,IAAMC,EAASF,EAAOG,gBAAgB,CAEpCC,qBAAqB,EACrBC,mBAAmB,EACnBC,kBAAkB,EAClBC,eAAe,IAGXC,IAAOhB,EACb,OAAO,IAAIiB,SAAiB,SAACC,EAASC,GAAW,IAAAC,EACzClB,EACakB,QADJA,EAAGV,EACfW,WAAW,aADID,IACCA,OADDA,EAAAA,EAEdE,aAAa,EAAG,EAAGZ,EAAOa,MAAOb,EAAOc,QAE5C,GAAKtB,EAEE,GAAKO,EAEL,CASLA,EAAOgB,iBAAiB,WARD,SAAjBC,EACJC,GAEIA,EAAExB,KAAKH,YAAcgB,IACvBP,EAAOmB,oBAAoB,UAAWF,GACtCR,EAAQS,EAAExB,KAAKI,mBAInBE,EAAOoB,YACL,CACE3B,UAAAA,EACAF,UAAWgB,GAEb,GAEJ,MAlBEE,EAAQjB,EAAuBC,SAF/BiB,GAqBJ,GACF,CAEAZ,EAAcuB,cAAgB,WAC5BL,iBACE,WACA,SAACE,GACC,IAAAI,EAAiCJ,EAAExB,KAA3BD,EAAS6B,EAAT7B,UAAWF,EAAS+B,EAAT/B,UACnB6B,YAAY,CACVtB,cAAeN,EAAuBC,GACtCF,UAAAA,GAEJ,GAEJ"}