Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a smooth corner painter works better with rectangles with a larger aspect ratio #152

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
}

.box,
.rect,
p {
display: grid;
place-items: center;
Expand All @@ -39,6 +40,12 @@
color: #fff;
}

.rect {
width: 10rem;
height: 30rem;
color: #fff;
}

.avatar {
width: 10rem;
height: 10rem;
Expand All @@ -50,7 +57,8 @@

.box,
.avatar,
.poster {
.poster,
.rect {
flex-shrink: 0;
object-fit: cover;
object-position: 50% 100%;
Expand All @@ -62,6 +70,42 @@
-webkit-mask-image: paint(smooth-corners);
}

.mask-v2 {
background: linear-gradient(#f34072, #d01257);
mask-image: paint(smooth-corners-v2);
-webkit-mask-image: paint(smooth-corners-v2);
}

.v2-5-1 {
--smooth-corners: 5;
--smooth-corners-radius: 1rem;
--smooth-corners-steps: 360;
}

.v2-5-1d5 {
--smooth-corners: 5;
--smooth-corners-radius: 1.5rem;
--smooth-corners-steps: 360;
}

.v2-5-0d5 {
--smooth-corners: 5;
--smooth-corners-radius: 0.5rem;
--smooth-corners-steps: 360;
}

.v2-4-1 {
--smooth-corners: 4;
--smooth-corners-radius: 1rem;
--smooth-corners-steps: 360;
}

.v2-2-1 {
--smooth-corners: 2;
--smooth-corners-radius: 1rem;
--smooth-corners-steps: 360;
}

.square {
--smooth-corners: 5;
}
Expand Down Expand Up @@ -323,6 +367,28 @@
</div>
</section>
<hr />
<section>
<p style="width:100%;">Update: add a smooth corner painter that better supports rectangle.</p>
</section>
<section>
<div>
<p>Original</p>
<img
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This image is missing a text alternative. This is a problem for people using screen readers.

src='https://media.kitsu.io/anime/poster_images/42722/large.jpg?1580402011'
class='rect mask v2-5-1'
/>
</div>
<div>
<p>V2</p>
<img
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This image is missing a text alternative. This is a problem for people using screen readers.

src='https://media.kitsu.io/anime/poster_images/42722/large.jpg?1580402011'
class='rect mask-v2 v2-5-1'
/>
</div>
<div class="rect mask-v2 v2-5-1">V2 5 R1</div>
<div class="rect mask-v2 v2-4-1">V2 4</div>
<div class="rect mask-v2 v2-2-1">V2 5</div>
</section>
<!-- Gradient -->
<section>
<div class='box special-16-2 mask'>16, 2</div>
Expand Down
76 changes: 76 additions & 0 deletions paint.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,83 @@ class SmoothCornersPainter {
ctx.closePath()
ctx.fill()
}
}

class SmoothCornerPainterV2 {
static get inputProperties() {
return ['--smooth-corners', '--smooth-corners-radius', '--smooth-corners-steps']
}


superellipse(a, b, nX = 4, nY, steps = 360) {
if (Number.isNaN(nX)) nX = 4
if (typeof nY === 'undefined' || Number.isNaN(nY)) nY = nX
if (nX > 100) nX = 100
if (nY > 100) nY = 100
if (nX < 0.00000000001) nX = 0.00000000001
if (nY < 0.00000000001) nY = 0.00000000001

const nX2 = 2 / nX
const nY2 = nY ? 2 / nY : nX2
const step = (2 * Math.PI) / steps
const points = t => {
const cosT = Math.cos(t)
const sinT = Math.sin(t)
return {
x: Math.abs(cosT) ** nX2 * a * Math.sign(cosT),
y: Math.abs(sinT) ** nY2 * b * Math.sign(sinT)
}
}
return Array.from({ length: steps }, (_, i) => points(i * step))
}

paint(ctx, size, props) {

const [nX, nY] = props
.get('--smooth-corners')
.toString()
.replace(/ /g, '')
.split(',')
.map(parseFloat)

const halfWidth = size.width / 2
const halfHeight = size.height / 2
const cornerRadius = Math.min(parseFloat(props.get('--smooth-corner-radius')) || size.width / 2, size.height / 2, size.width / 2)
const steps = parseFloat(props.get('--smooth-corner-steps')) || 360
const smoothCorners = this.superellipse(
cornerRadius,
cornerRadius,
nX,
nY,
steps
)

const xOffset = halfWidth - cornerRadius
const yOffset = halfHeight - cornerRadius

const leftBottomCorners = smoothCorners.slice(0, steps / 4).map(({ x, y }) => ({ x: x + xOffset, y: y + yOffset }))
const rightBottomCorners = smoothCorners.slice(steps / 4, steps / 2).map(({ x, y }) => ({ x: x - xOffset, y: y + yOffset }))
const rightTopCorners = smoothCorners.slice(steps / 2, steps * 3 / 4).map(({ x, y }) => ({ x: x - xOffset, y: y - yOffset }))
const leftTopCorners = smoothCorners.slice(steps * 3 / 4, steps).map(({ x, y }) => ({ x: x + xOffset, y: y - yOffset }))
const points = [...leftBottomCorners, ...rightBottomCorners, ...rightTopCorners, ...leftTopCorners]

ctx.fillStyle = '#000'
ctx.setTransform(1, 0, 0, 1, halfWidth, halfHeight)
ctx.beginPath()
points.forEach(({ x, y }, i) => {
if (i === 0) ctx.moveTo(x, y)
else ctx.lineTo(x, y)
})
ctx.closePath()
ctx.fill()

}




}

// eslint-disable-next-line no-undef
registerPaint('smooth-corners', SmoothCornersPainter)
registerPaint('smooth-corners-v2', SmoothCornerPainterV2)