<span class="supt-line">
<span class="supt-line__inner"></span>
</span>
No notes defined.
<span class="supt-line">
<span class="supt-line__inner"></span>
</span>
/* No context defined. */
import { animate, JSAnimation, onScroll } from 'animejs';
import { Sizes } from '@/js/Sizes';
import { BREAKPOINTS } from '@/js/constants';
export interface LineOptions {
scale: {
mobile: {
x: number[];
y: number[];
};
desktop: {
x: number[];
y: number[];
};
};
threshold: {
enter: string;
leave?: string;
};
sync?: boolean | string;
desktopBreakpoint?: (typeof BREAKPOINTS)[keyof typeof BREAKPOINTS];
}
export class Line {
$element: HTMLElement;
$container: HTMLElement;
$inner: HTMLElement;
options: LineOptions;
sizes: Sizes;
animation: JSAnimation | null = null;
constructor($element: HTMLElement, $container: HTMLElement, options: LineOptions) {
this.$element = $element;
this.$container = $container;
this.$inner = this.$element.querySelector('.supt-line__inner') as HTMLElement;
this.options = options;
this.sizes = new Sizes(); // Use Singleton
this.init();
window.addEventListener('resize', this.handleResize.bind(this));
}
init() {
if (this.animation) {
this.animation.cancel();
}
const scaleX =
this.sizes.currentWidth >= (this.options.desktopBreakpoint ?? BREAKPOINTS.md)
? this.options.scale.desktop.x
: this.options.scale.mobile.x;
const scaleY =
this.sizes.currentWidth >= (this.options.desktopBreakpoint ?? BREAKPOINTS.md)
? this.options.scale.desktop.y
: this.options.scale.mobile.y;
this.animation = animate(this.$inner, {
scaleX,
scaleY,
ease: 'linear',
autoplay: onScroll({
container: document.body,
target: this.$container,
enter: this.options.threshold.enter,
leave: this.options.threshold.leave,
sync: this.options.sync ?? true,
}),
});
}
private handleResize(): void {
this.init();
}
}
export class LineGlow {
$element: HTMLElement;
$container: HTMLElement;
$glow: HTMLElement;
options: LineOptions;
sizes: Sizes;
animation: JSAnimation | null = null;
constructor($element: HTMLElement, $container: HTMLElement, options: LineOptions) {
this.$element = $element;
this.$container = $container;
this.$glow = this.$element.querySelector('.supt-line__glow') as HTMLElement;
this.options = options;
this.sizes = new Sizes(); // Use Singleton
this.init();
window.addEventListener('resize', this.handleResize.bind(this));
}
init() {
if (this.animation) {
this.animation.cancel();
}
const height = this.$element.offsetHeight / 1.2 + 2;
this.$glow.style.strokeDasharray = `${height}`;
this.animation = animate(this.$glow, {
strokeDashoffset: [height, 0],
ease: 'linear',
autoplay: onScroll({
container: document.body,
target: this.$container,
enter: this.options.threshold.enter,
leave: this.options.threshold.leave,
sync: this.options.sync ?? true,
}),
});
}
private handleResize(): void {
this.init();
}
}
.supt-line {
pointer-events: none;
&:not(.-glow) {
display: block;
width: var(--line-xs-width);
height: var(--line-xs-height);
background-color: $color-grey-2;
@media (min-width: $breakpoint-md) {
width: var(--line-md-width);
height: var(--line-md-height);
}
.supt-line__inner {
position: absolute;
top: 0;
left: 0;
width: var(--line-xs-width);
height: var(--line-xs-height);
background-color: $color-main;
transform-origin: top;
@media (min-width: $breakpoint-md) {
width: var(--line-md-width);
height: var(--line-md-height);
}
}
}
&.-glow {
position: relative;
width: 100%;
height: 100%;
.supt-line__line {
position: relative;
display: block;
width: 1px;
height: 100%;
background-color: $color-new;
left: 50%;
transform: translateX(-50%);
}
.supt-line__glow {
position: absolute;
top: 0;
left: calc(-50% + 1px);
width: auto;
height: 100%;
transform-origin: top;
overflow: visible;
transform: scaleY(1.2) translateX(-50%);
stroke-dasharray: 600;
}
}
}