Add Squiggly component
This component lets you render text with a configurable squiggly line underneath
This commit is contained in:
parent
3580b5d3da
commit
54727edc36
1 changed files with 83 additions and 0 deletions
83
src/lib/components/Squiggly.svelte
Normal file
83
src/lib/components/Squiggly.svelte
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
|
export let text = 'Hello, Squiggly World!'
|
||||||
|
export let frequency = 0.4
|
||||||
|
export let amplitude = 1.5
|
||||||
|
export let color = '#ff0000'
|
||||||
|
export let distance = 3
|
||||||
|
export let lineWidth = 1.75
|
||||||
|
|
||||||
|
let textWidth = 0
|
||||||
|
let textElement: HTMLHeadingElement
|
||||||
|
let squigglyHeight: number
|
||||||
|
|
||||||
|
$: path = generatePath(textWidth, frequency, amplitude, distance)
|
||||||
|
$: squigglyHeight = distance + amplitude * 2 + lineWidth
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
updateTextWidth()
|
||||||
|
})
|
||||||
|
|
||||||
|
function updateTextWidth(): void {
|
||||||
|
textWidth = textElement?.getBoundingClientRect().width || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function generatePath(width: number, freq: number, amp: number, dist: number): string {
|
||||||
|
if (width === 0) return ''
|
||||||
|
const startX = 2
|
||||||
|
const endX = width - 2
|
||||||
|
const startY = amp * Math.sin(startX * freq) + dist
|
||||||
|
|
||||||
|
let pathData = `M${startX},${startY} `
|
||||||
|
|
||||||
|
for (let x = startX; x <= endX; x++) {
|
||||||
|
const y = amp * Math.sin(x * freq) + dist
|
||||||
|
pathData += `L${x},${y} `
|
||||||
|
}
|
||||||
|
return pathData
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
text // add this as a dependency
|
||||||
|
updateTextWidth()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="squiggly-container" style="padding-bottom: {squigglyHeight}px;">
|
||||||
|
<h2 bind:this={textElement} class="squiggly-header" style="color: {color}">{text}</h2>
|
||||||
|
<svg
|
||||||
|
class="squiggly-underline"
|
||||||
|
width={textWidth}
|
||||||
|
height={squigglyHeight}
|
||||||
|
viewBox="0 0 {textWidth} {squigglyHeight}"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d={path}
|
||||||
|
fill="none"
|
||||||
|
stroke={color}
|
||||||
|
stroke-width={lineWidth}
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.squiggly-header {
|
||||||
|
font-size: $font-size;
|
||||||
|
font-weight: 400;
|
||||||
|
margin-bottom: $unit-fourth;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squiggly-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.squiggly-underline {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in a new issue