UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

1 lines 8.76 kB
{"version":3,"file":"SprayBrush.min.mjs","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 * @default\n */\n width = 10;\n\n /**\n * Density of a spray (number of dots per chunk)\n * @type Number\n * @default\n */\n density = 20;\n\n /**\n * Width of spray dots\n * @type Number\n * @default\n */\n dotWidth = 1;\n\n /**\n * Width variance of spray dots\n * @type Number\n * @default\n */\n dotWidthVariance = 1;\n\n /**\n * Whether opacity of a dot should be random\n * @type Boolean\n * @default\n */\n randomOpacity = false;\n\n /**\n * Whether overlapping dots (rectangles) should be removed (for performance reasons)\n * @type Boolean\n * @default\n */\n optimizeOverlapping = true;\n\n private declare sprayChunks: SprayBrushPoint[][];\n\n private declare 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"],"names":["SprayBrush","BaseBrush","constructor","canvas","super","_defineProperty","this","sprayChunks","sprayChunk","onMouseDown","pointer","clearContext","contextTop","_setShadow","addSprayChunk","renderChunck","onMouseMove","limitedToCanvasSize","_isOutSideCanvas","onMouseUp","originalRenderOnAddRemove","renderOnAddRemove","rects","i","length","j","chunck","rect","Rect","width","height","left","x","top","y","originX","CENTER","originY","fill","color","push","group","Group","optimizeOverlapping","uniqueRects","uniqueRectsArray","key","concat","getUniqueRects","objectCaching","subTargetCheck","interactive","shadow","set","Shadow","fire","path","add","_resetShadow","requestRenderAll","sprayChunck","ctx","fillStyle","_saveAndTransform","point","globalAlpha","opacity","fillRect","restore","_render","radius","density","getRandomInt","dotWidthVariance","Math","max","dotWidth","randomOpacity"],"mappings":"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"}