fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
1 lines • 7.68 kB
Source Map (JSON)
{"version":3,"file":"SprayBrush.min.mjs","names":[],"sources":["../../../src/brushes/SprayBrush.ts"],"sourcesContent":["import type { Point } from '../Point';\nimport { Group } from '../shapes/Group';\nimport { Shadow } from '../Shadow';\nimport { Rect } from '../shapes/Rect';\nimport { getRandomInt } from '../util/internals/getRandomInt';\nimport type { Canvas } from '../canvas/Canvas';\nimport { BaseBrush } from './BaseBrush';\nimport type { SprayBrushPoint } from './typedefs';\nimport { CENTER } from '../constants';\n\n/**\n *\n * @param rects\n * @returns\n */\nfunction getUniqueRects(rects: Rect[]) {\n const uniqueRects: Record<string, boolean> = {};\n const uniqueRectsArray: Rect[] = [];\n\n for (let i = 0, key: string; i < rects.length; i++) {\n key = `${rects[i].left}${rects[i].top}`;\n if (!uniqueRects[key]) {\n uniqueRects[key] = true;\n uniqueRectsArray.push(rects[i]);\n }\n }\n\n return uniqueRectsArray;\n}\n\nexport class SprayBrush extends BaseBrush {\n /**\n * Width of a spray\n * @type Number\n */\n width = 10;\n\n /**\n * Density of a spray (number of dots per chunk)\n * @type Number\n */\n density = 20;\n\n /**\n * Width of spray dots\n * @type Number\n */\n dotWidth = 1;\n\n /**\n * Width variance of spray dots\n * @type Number\n */\n dotWidthVariance = 1;\n\n /**\n * Whether opacity of a dot should be random\n * @type Boolean\n */\n randomOpacity = false;\n\n /**\n * Whether overlapping dots (rectangles) should be removed (for performance reasons)\n * @type Boolean\n */\n optimizeOverlapping = true;\n\n declare private sprayChunks: SprayBrushPoint[][];\n\n declare private sprayChunk: SprayBrushPoint[];\n\n /**\n * Constructor\n * @param {Canvas} canvas\n * @return {SprayBrush} Instance of a spray brush\n */\n constructor(canvas: Canvas) {\n super(canvas);\n this.sprayChunks = [];\n this.sprayChunk = [];\n }\n\n /**\n * Invoked on mouse down\n * @param {Point} pointer\n */\n onMouseDown(pointer: Point) {\n this.sprayChunks = [];\n this.canvas.clearContext(this.canvas.contextTop);\n this._setShadow();\n\n this.addSprayChunk(pointer);\n this.renderChunck(this.sprayChunk);\n }\n\n /**\n * Invoked on mouse move\n * @param {Point} pointer\n */\n onMouseMove(pointer: Point) {\n if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {\n return;\n }\n this.addSprayChunk(pointer);\n this.renderChunck(this.sprayChunk);\n }\n\n /**\n * Invoked on mouse up\n */\n onMouseUp() {\n const originalRenderOnAddRemove = this.canvas.renderOnAddRemove;\n this.canvas.renderOnAddRemove = false;\n\n const rects: Rect[] = [];\n\n for (let i = 0; i < this.sprayChunks.length; i++) {\n const sprayChunk = this.sprayChunks[i];\n for (let j = 0; j < sprayChunk.length; j++) {\n const chunck = sprayChunk[j];\n const rect = new Rect({\n width: chunck.width,\n height: chunck.width,\n left: chunck.x + 1,\n top: chunck.y + 1,\n originX: CENTER,\n originY: CENTER,\n fill: this.color,\n });\n rects.push(rect);\n }\n }\n\n const group = new Group(\n this.optimizeOverlapping ? getUniqueRects(rects) : rects,\n {\n objectCaching: true,\n subTargetCheck: false,\n interactive: false,\n },\n );\n this.shadow && group.set('shadow', new Shadow(this.shadow));\n this.canvas.fire('before:path:created', { path: group });\n this.canvas.add(group);\n this.canvas.fire('path:created', { path: group });\n\n this.canvas.clearContext(this.canvas.contextTop);\n this._resetShadow();\n this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n this.canvas.requestRenderAll();\n }\n\n renderChunck(sprayChunck: SprayBrushPoint[]) {\n const ctx = this.canvas.contextTop;\n ctx.fillStyle = this.color;\n\n this._saveAndTransform(ctx);\n\n for (let i = 0; i < sprayChunck.length; i++) {\n const point = sprayChunck[i];\n ctx.globalAlpha = point.opacity;\n ctx.fillRect(point.x, point.y, point.width, point.width);\n }\n\n ctx.restore();\n }\n\n /**\n * Render all spray chunks\n */\n _render() {\n const ctx = this.canvas.contextTop;\n ctx.fillStyle = this.color;\n\n this._saveAndTransform(ctx);\n\n for (let i = 0; i < this.sprayChunks.length; i++) {\n this.renderChunck(this.sprayChunks[i]);\n }\n ctx.restore();\n }\n\n /**\n * @param {Point} pointer\n */\n addSprayChunk(pointer: Point) {\n this.sprayChunk = [];\n const radius = this.width / 2;\n\n for (let i = 0; i < this.density; i++) {\n this.sprayChunk.push({\n x: getRandomInt(pointer.x - radius, pointer.x + radius),\n y: getRandomInt(pointer.y - radius, pointer.y + radius),\n width: this.dotWidthVariance\n ? getRandomInt(\n // bottom clamp width to 1\n Math.max(1, this.dotWidth - this.dotWidthVariance),\n this.dotWidth + this.dotWidthVariance,\n )\n : this.dotWidth,\n opacity: this.randomOpacity ? getRandomInt(0, 100) / 100 : 1,\n });\n }\n\n this.sprayChunks.push(this.sprayChunk);\n }\n}\n"],"mappings":"2ZA8BA,IAAa,EAAb,cAAgC,CAAA,CA8C9B,YAAY,EAAA,CACV,MAAM,EAAA,CAAA,EAAA,KA1CR,QAAQ,GAAA,CAAA,EAAA,KAMR,UAAU,GAAA,CAAA,EAAA,KAMV,WAAW,EAAA,CAAA,EAAA,KAMX,mBAAmB,EAAA,CAAA,EAAA,KAMnB,gBAAA,CAAgB,EAAA,CAAA,EAAA,KAMhB,sBAAA,CAAsB,EAAA,CAapB,KAAK,YAAc,EAAA,CACnB,KAAK,WAAa,EAAA,CAOpB,YAAY,EAAA,CACV,KAAK,YAAc,EAAA,CACnB,KAAK,OAAO,aAAa,KAAK,OAAO,WAAA,CACrC,KAAK,YAAA,CAEL,KAAK,cAAc,EAAA,CACnB,KAAK,aAAa,KAAK,WAAA,CAOzB,YAAY,EAAA,CAAA,CACuB,IAA7B,KAAK,qBAAgC,KAAK,iBAAiB,EAAA,GAG/D,KAAK,cAAc,EAAA,CACnB,KAAK,aAAa,KAAK,WAAA,EAMzB,WAAA,CACE,IAAM,EAA4B,KAAK,OAAO,kBAC9C,KAAK,OAAO,kBAAA,CAAoB,EAEhC,IAAM,EAAgB,EAAA,CAEtB,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,YAAY,OAAQ,IAAK,CAChD,IAAM,EAAa,KAAK,YAAY,GACpC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,OAAQ,IAAK,CAC1C,IAAM,EAAS,EAAW,GACpB,EAAO,IAAI,EAAK,CACpB,MAAO,EAAO,MACd,OAAQ,EAAO,MACf,KAAM,EAAO,EAAI,EACjB,IAAK,EAAO,EAAI,EAChB,QAAS,EACT,QAAS,EACT,KAAM,KAAK,MAAA,CAAA,CAEb,EAAM,KAAK,EAAA,EAIf,IAAM,EAAQ,IAAI,EAChB,KAAK,oBAvHX,SAAwB,EAAA,CACtB,IAAM,EAAuC,EAAA,CACvC,EAA2B,EAAA,CAEjC,IAAK,IAAW,EAAP,EAAI,EAAgB,EAAI,EAAM,OAAQ,IAC7C,EAAM,GAAG,EAAM,GAAG,OAAO,EAAM,GAAG,MAC7B,EAAY,KACf,EAAY,GAAA,CAAO,EACnB,EAAiB,KAAK,EAAM,GAAA,EAIhC,OAAO,GA2GuC,EAAA,CAAS,EACnD,CACE,cAAA,CAAe,EACf,eAAA,CAAgB,EAChB,YAAA,CAAa,EAAA,CAAA,CAGjB,KAAK,QAAU,EAAM,IAAI,SAAU,IAAI,EAAO,KAAK,OAAA,CAAA,CACnD,KAAK,OAAO,KAAK,sBAAuB,CAAE,KAAM,EAAA,CAAA,CAChD,KAAK,OAAO,IAAI,EAAA,CAChB,KAAK,OAAO,KAAK,eAAgB,CAAE,KAAM,EAAA,CAAA,CAEzC,KAAK,OAAO,aAAa,KAAK,OAAO,WAAA,CACrC,KAAK,cAAA,CACL,KAAK,OAAO,kBAAoB,EAChC,KAAK,OAAO,kBAAA,CAGd,aAAa,EAAA,CACX,IAAM,EAAM,KAAK,OAAO,WACxB,EAAI,UAAY,KAAK,MAErB,KAAK,kBAAkB,EAAA,CAEvB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAY,OAAQ,IAAK,CAC3C,IAAM,EAAQ,EAAY,GAC1B,EAAI,YAAc,EAAM,QACxB,EAAI,SAAS,EAAM,EAAG,EAAM,EAAG,EAAM,MAAO,EAAM,MAAA,CAGpD,EAAI,SAAA,CAMN,SAAA,CACE,IAAM,EAAM,KAAK,OAAO,WACxB,EAAI,UAAY,KAAK,MAErB,KAAK,kBAAkB,EAAA,CAEvB,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,YAAY,OAAQ,IAC3C,KAAK,aAAa,KAAK,YAAY,GAAA,CAErC,EAAI,SAAA,CAMN,cAAc,EAAA,CACZ,KAAK,WAAa,EAAA,CAClB,IAAM,EAAS,KAAK,MAAQ,EAE5B,IAAK,IAAI,EAAI,EAAG,EAAI,KAAK,QAAS,IAChC,KAAK,WAAW,KAAK,CACnB,EAAG,EAAa,EAAQ,EAAI,EAAQ,EAAQ,EAAI,EAAA,CAChD,EAAG,EAAa,EAAQ,EAAI,EAAQ,EAAQ,EAAI,EAAA,CAChD,MAAO,KAAK,iBACR,EAEE,KAAK,IAAI,EAAG,KAAK,SAAW,KAAK,iBAAA,CACjC,KAAK,SAAW,KAAK,iBAAA,CAEvB,KAAK,SACT,QAAS,KAAK,cAAgB,EAAa,EAAG,IAAA,CAAO,IAAM,EAAA,CAAA,CAI/D,KAAK,YAAY,KAAK,KAAK,WAAA,GAAA,OAAA,KAAA"}