diff --git a/factors/smooth-corners.js b/factors/smooth-corners.js index 53dd029..9c41c8d 100644 --- a/factors/smooth-corners.js +++ b/factors/smooth-corners.js @@ -1,23 +1,173 @@ -class SmoothCorners { - static get inputProperties() { - return ['--smooth-radius']; - } - - paint(ctx, geom, properties) { - const radius = parseFloat(properties.get('--smooth-radius')) || 20; - const width = geom.width; - const height = geom.height; - - ctx.fillStyle = 'black'; - ctx.beginPath(); - ctx.moveTo(radius, 0); - ctx.arcTo(width, 0, width, height, radius); - ctx.arcTo(width, height, 0, height, radius); - ctx.arcTo(0, height, 0, 0, radius); - ctx.arcTo(0, 0, width, 0, radius); - ctx.closePath(); - ctx.fill(); - } -} - -registerPaint('smooth-corners', SmoothCorners); + + const drawSquircle = (ctx, geom, corners, radius, smooth, lineWidth, color) => { + const defaultFill = color; + const lineWidthOffset = lineWidth / 2; + + // OPEN LEFT-TOP CORNER + ctx.beginPath(); + // ctx.lineTo(radius, lineWidthOffset); + + // TOP-RIGHT CORNER + if (corners.has('top-right')) { + ctx.lineTo(geom.width - radius, lineWidthOffset); + ctx.bezierCurveTo( + geom.width - radius / smooth, + lineWidthOffset, // first bezier point + geom.width - lineWidthOffset, + radius / smooth, // second bezier point + geom.width - lineWidthOffset, + radius // last connect point + ); + } else { + ctx.lineTo(geom.width - lineWidthOffset, lineWidthOffset); + } + + // BOTTOM-RIGHT CORNER + if (corners.has('bottom-right')) { + ctx.lineTo(geom.width - lineWidthOffset, geom.height - radius); + ctx.bezierCurveTo( + geom.width - lineWidthOffset, + geom.height - radius / smooth, // first bezier point + geom.width - radius / smooth, + geom.height - lineWidthOffset, // second bezier point + geom.width - radius, + geom.height - lineWidthOffset // last connect point + ); + } else { + ctx.lineTo(geom.width - lineWidthOffset, geom.height - lineWidthOffset); + } + + // BOTTOM-LEFT CORNER + if (corners.has('bottom-left')) { + ctx.lineTo(radius, geom.height - lineWidthOffset); + ctx.bezierCurveTo( + radius / smooth, + geom.height - lineWidthOffset, // first bezier point + lineWidthOffset, + geom.height - radius / smooth, // second bezier point + lineWidthOffset, + geom.height - radius // last connect point + ); + } else { + ctx.lineTo(lineWidthOffset, geom.height - lineWidthOffset); + } + + // CLOSE LEFT-TOP CORNER + if (corners.has('top-left')) { + ctx.lineTo(lineWidthOffset, radius); + ctx.bezierCurveTo( + lineWidthOffset, + radius / smooth, // first bezier point + radius / smooth, + lineWidthOffset, // second bezier point + radius, + lineWidthOffset // last connect point + ); + } else { + ctx.lineTo(lineWidthOffset, lineWidthOffset); + } + + ctx.closePath(); + + if (lineWidth) { + ctx.strokeStyle = defaultFill; + ctx.lineWidth = lineWidth; + ctx.stroke(); + } else { + ctx.fillStyle = defaultFill; + ctx.fill(); + } + }; + + if (typeof registerPaint !== "undefined") { + class SquirclePainter { + static get contextOptions() { + return { alpha: true }; + } + static get inputProperties() { + return [ + "--squircle-radius", + "--squircle-smooth", + "--squircle-outline", + "--squircle-fill", + "--squircle-ratio", + "--squircle-corners", + ]; + } + + paint(ctx, geom, properties) { + const customRatio = properties.get("--squircle-ratio"); + const smoothRatio = 10; + const distanceRatio = parseFloat(customRatio) + ? parseFloat(customRatio) + : 1.8; + const squircleSmooth = parseFloat( + properties.get("--squircle-smooth") * smoothRatio + ); + const squircleRadius = + parseInt(properties.get("--squircle-radius"), 10) * distanceRatio; + const squrcleOutline = parseFloat( + properties.get("--squircle-outline"), + 10 + ); + const squircleColor = properties + .get("--squircle-fill") + .toString() + .replace(/s/g, ""); + + const isSmooth = () => { + if (typeof properties.get("--squircle-smooth")[0] !== "undefined") { + if (squircleSmooth === 0) { + return 1; + } + return squircleSmooth; + } else { + return 10; + } + }; + + const isOutline = () => { + if (squrcleOutline) { + return squrcleOutline; + } else { + return 0; + } + }; + + const isColor = () => { + if (squircleColor) { + return squircleColor; + } else { + return "#2f2f2f"; + } + }; + + const corners = new Set(properties.get('--squircle-corners')?.[0]?.split(' ')); + + if (squircleRadius < geom.width / 2 && squircleRadius < geom.height / 2) { + drawSquircle( + ctx, + geom, + corners, + squircleRadius, + isSmooth(), + isOutline(), + isColor() + ); + } else { + drawSquircle( + ctx, + geom, + corners, + Math.min(geom.width / 2, geom.height / 2), + isSmooth(), + isOutline(), + isColor() + ); + } + } + } + + registerPaint("squircle", SquirclePainter); + } +