/* * Title: Brushes module * Author: AlekPet * Github: https://github.com/AlekPet * Github extensions ComfyUI: https://github.com/AlekPet/ComfyUI_Custom_Nodes_AlekPet */ import { fabric } from "./fabric.js"; import { rangeGradient } from "./helpers.js"; // Brush symmetry fabricjs fabric.SymmetryBrush = fabric.util.createClass(fabric.BaseBrush, { initialize: function (canvas) { this.canvas = canvas; this.ctx = canvas.contextTop; this._options = { // Normal default: { points: [], enable: true, type: "x=x,y=y" }, // x=x,y=y width_heigth: { points: [], enable: false, type: "x=w-x,y=h-y" }, // x=w-x,y=h-y width_x: { points: [], enable: true, type: "x=w-x,y=y" }, // x=w-x,y=y heigth_y: { points: [], enable: false, type: "x=x,y=h-y" }, // x=x,y=h-y // Reverse rev_default: { points: [], enable: false, type: "x=y,y=x" }, // x=y,y=x rev_width_heigth: { points: [], enable: false, type: "x=h-y,y=w-x" }, // x=h-y,y=w-x rev_width_x: { points: [], enable: false, type: "x=h-y,y=x" }, // x=h-y,y=x rev_heigth_y: { points: [], enable: false, type: "x=y,y=w-x" }, // x=y,y=w-x }; }, _updatePoints: function (options) { // Normal this._options["default"].points.push( new fabric.Point(options.pointer.x, options.pointer.y) ); this._options["width_heigth"].points.push( new fabric.Point( this.canvas.width - options.pointer.x, this.canvas.height - options.pointer.y ) ); this._options["width_x"].points.push( new fabric.Point(this.canvas.width - options.pointer.x, options.pointer.y) ); this._options["heigth_y"].points.push( new fabric.Point( options.pointer.x, this.canvas.height - options.pointer.y ) ); // Reverse this._options["rev_default"].points.push( new fabric.Point(options.pointer.y, options.pointer.x) ); this._options["rev_width_heigth"].points.push( new fabric.Point( this.canvas.height - options.pointer.y, this.canvas.width - options.pointer.x ) ); this._options["rev_width_x"].points.push( new fabric.Point( this.canvas.height - options.pointer.y, options.pointer.x ) ); this._options["rev_heigth_y"].points.push( new fabric.Point(options.pointer.y, this.canvas.width - options.pointer.x) ); }, convertPointsToSVGPath: function (points) { var correction = this.width / 1000; return fabric.util.getSmoothPathFromPoints(points, correction); }, _render() {}, _drawSegment: function (mP, toP) { const ctx = this.ctx; ctx.save(); ctx.beginPath(); ctx.strokeStyle = this.color; ctx.lineCap = this.strokeLineCap; ctx.lineJoin = this.strokeLineJoin; ctx.lineWidth = this.width; ctx.moveTo(mP.x, mP.y); ctx.lineTo(toP.x, toP.y); ctx.stroke(); ctx.restore(); }, createPath: function (pathData, shadow = false) { var path = new fabric.Path(pathData, { fill: null, stroke: this.color, strokeWidth: this.width, strokeLineCap: this.strokeLineCap, strokeMiterLimit: this.strokeMiterLimit, strokeLineJoin: this.strokeLineJoin, strokeDashArray: this.strokeDashArray, }); if (this.shadow) { this.shadow.affectStroke = true; path.shadow = new fabric.Shadow(this.shadow); } return path; }, onMouseDown: function (pointer, options) { if (!this.canvas._isMainEvent(options.e)) { return; } this._updatePoints(options); }, onMouseMove: function (pointer, options) { if (!this.canvas._isMainEvent(options.e)) { return; } if (options.e.buttons !== 1) return; if (this._options["default"].points.length > 1) { for (let p_key in this._options) { const pointVal = this._options[p_key]; if (pointVal.enable && pointVal.points.length > 0) { this._drawSegment( pointVal.points[pointVal.points.length - 2], pointVal.points[pointVal.points.length - 1] ); } } } this._updatePoints(options); this.canvas.renderAll(); }, onMouseUp: function (options) { if (!this.canvas._isMainEvent(options.e)) { return true; } for (let p_key in this._options) { const pointVal = this._options[p_key]; if (pointVal.enable && pointVal.points.length > 1) { const path = this.convertPointsToSVGPath(pointVal.points); const offsetPath = this.createPath(path); this.canvas.add(offsetPath); } this._options[p_key].points = []; } return false; }, }); // MyPaintBrush symmetry fabric.MyBrushPaintSymmetry = fabric.util.createClass(fabric.SymmetryBrush, { initialize: function ( canvas, range_brush_pressure = null, brushSettings = null ) { this.callSuper("initialize", canvas); if (!brushSettings) { throw new Error("Not valid brush settings!"); } this.brushSettings = brushSettings; this._options.width_x.enable = false; this.surface = new MypaintSurface(this.canvas); this.brush = new MypaintBrush(this.brushSettings, this.surface); this.range_brush_pressure = range_brush_pressure; this.newGroup(); }, newGroup: function () { this.group = new fabric.Group(); const scaleFactor = window.devicePixelRatio; Object.assign(this.group, { width: this.canvas.width * scaleFactor, height: this.canvas.height * scaleFactor, strokeWidth: 0, originX: "left", originY: "top", left: 0, top: 0, mypaintlib: true, }); this.canvas.add(this.group); }, onMouseDown: function (pointer, options) { if (!this.canvas._isMainEvent(options.e)) { return; } if (!this.canvas.getObjects().length) { this.newGroup(); } this._updatePoints(options); this.t1 = new Date().getTime(); this.brush.new_stroke(pointer.x, pointer.y); }, onMouseMove: function (pointer, options) { if (!this.canvas._isMainEvent(options.e)) { return; } if (options.e.buttons !== 1) return; let pressure; let { pressure: pressurePointer, pointerType } = options.e; // Pen if (pointerType === "pen") { // Pointer pressure if (!pressure) pressure = pressurePointer; if ((!pressure && !pressurePointer) || pressure === 0) pressure = parseFloat(this.range_brush_pressure.value); } // Mouse if (pointerType === "mouse" || pointerType === "touch") { if (pressure === undefined || pressure === 0) { pressure = parseFloat(this.range_brush_pressure.value); } } this.range_brush_pressure.nextElementSibling.textContent = pressure.toFixed(2); this.range_brush_pressure.style.background = rangeGradient( this.range_brush_pressure ); const time = (new Date().getTime() - this.t1) / 1000; if (this._options["default"].points.length > 1) { for (let p_key in this._options) { const pointVal = this._options[p_key]; if (pointVal.enable && pointVal.points.length > 1) { this.brush.states[0] = pointVal.points[pointVal.points.length - 2].x; this.brush.states[1] = pointVal.points[pointVal.points.length - 2].y; this.brush.stroke_to( pointVal.points[pointVal.points.length - 1].x, pointVal.points[pointVal.points.length - 1].y, pressure, 90, 0, time ); } } } this._updatePoints(options); this.canvas.renderAll(); }, onMouseUp: function (options) { if (!this.canvas._isMainEvent(options.e)) { return true; } const canvasToImage = this.canvas.upperCanvasEl.toDataURL(); fabric.Image.fromURL(canvasToImage, (myImg) => { const scaleFactor = window.devicePixelRatio; const imageCanv = myImg.set({ left: this.group.left, top: this.group.top, originX: "left", originY: "top", scaleX: myImg.scaleX / scaleFactor, scaleY: myImg.scaleY / scaleFactor, mypaintlib: true, }); this.canvas.clearContext(this.ctx); this.group.addWithUpdate(imageCanv); this.group.setCoords(); this.canvas.add(new fabric.Image("")); // empty object, hook this.canvas.requestRenderAll(); }); Object.keys(this._options).forEach( (p_key) => (this._options[p_key].points = []) ); return false; }, }); const svgSymmetryButtons = [ ` `, ` `, ` `, ` `, ` `, ` `, ` `, ` `, ]; export { svgSymmetryButtons };