JSFiddle - React, Tailwind, and code Playground
Paint API border experiment
by Travis Almand
HTML
<div class="container">
account 1
</div>
<div class="container">
account 2
</div>
<div class="container">
account 3
</div>
SCSS
.container {
align-items: center;
background-color: white;
border-radius: 10px;
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.5);
display: flex;
height: 100px;
justify-content: center;
margin: 20px;
position: relative;
overflow: hidden;
width: 300px;
// you can adjust these
--decorate-width: 14;
--decorate-color: rgba(255,0,0,1);
--decorate-duration: 500;
// don't adjust these
--decorate-x: 0;
--decorate-y: 0;
--decorate-tick: 0;
&.decorate {
background-image: paint(decorate);
}
}
JavaScript
console.clear();
let accountContainers = document.querySelectorAll('.container');
accountContainers.forEach(container => {
container.addEventListener('mouseover', function (e) {
this.classList.toggle('decorate');
let self = this;
let start = performance.now();
let rect = self.getBoundingClientRect();
let x = e.clientX - rect.x;
let y = e.clientY - rect.y;
let duration = getComputedStyle(self).getPropertyValue('--decorate-duration');
requestAnimationFrame(function raf(now) {
const count = Math.floor(now - start);
self.style.cssText = `--decorate-x: ${x}; --decorate-y: ${y}; --decorate-tick: ${count};`;
if(count > duration) {
return;
}
requestAnimationFrame(raf);
});
});
container.addEventListener('mouseout', function (e) {
this.classList.remove('decorate');
this.style.cssText = '--decorate-tick: 0';
})
});
CSS.paintWorklet.addModule(URL.createObjectURL(new Blob([`
class AccountDecorator {
static get inputProperties() { return ['background-color', '--decorate-color', '--decorate-tick', '--decorate-x', '--decorate-y', '--decorate-width', '--decorate-duration']; }
paint(ctx, geom, properties) {
const backgroundColor = properties.get('background-color').toString();
const color = properties.get('--decorate-color').toString();
const x = parseFloat(properties.get('--decorate-x'));
const y = parseFloat(properties.get('--decorate-y'));
const width = parseFloat(properties.get('--decorate-width'));
const duration = parseFloat(properties.get('--decorate-duration'));
let tick = parseFloat(properties.get('--decorate-tick').toString());
if(tick < 0) { tick = 0 };
if(tick > duration) { tick = duration };
//console.log("x: " + x + " y: " + y);
const lineLength = (geom.width * 2) + (geom.height * 2);
const stepsLength = lineLength / duration;
const currentLength = stepsLength * tick;
...