import {c, css, html, useEffect, useHost, useRef, useState} from "atomico";
declare global {
namespace JSX {
interface IntrinsicElements {
"c-svg": any;
}
}
var htmx: any;
}
function styleSvgPath(path:SVGPathElement) {
const length = path.getTotalLength();
path.style.stroke = "rgb(107 114 128 )" // Red stroke for high visibility
path.style.strokeWidth = '2';
path.style.fill = 'white'; // No fill initially to ensure stroke visibility
// Set the stroke-dasharray and dashoffset to create the drawing effect
// path.style.strokeDasharray = length;
// path.style.strokeDashoffset = length;
path.style.fillOpacity ="70%"
// Add the animation class to animate the stroke
path.classList.add('draw-path');
}
async function* fetchSvgInBatches(src: string) {
const response = await fetch(src);
const reader = response.body?.getReader();
const decoder = new TextDecoder();
let done = false;
let svgContent = '';
let yieldPaths:SVGPathElement[] = [];
while (!done) {
const { value, done: readerDone } = await reader?.read() || { value: undefined, done: true };
done = readerDone;
svgContent += decoder.decode(value, { stream: !done });
const dom = new DOMParser().parseFromString(svgContent, 'image/svg+xml');
const paths = Array.from(dom.querySelectorAll('path'));
for (const path of paths.filter(path => !yieldPaths.includes(path))) {
yield {path, svgElement: dom.documentElement};
yieldPaths.push(path);
await new Promise(resolve => setTimeout(resolve, 200));
}
}
}
export const SVG = c(function ({ src }) {
const [svgPaths, setSvgPaths] = useState([] as SVGPathElement[]);
const svgElement = useRef();
useEffect(() => {
const loadSvg = async () => {
for await (const { path, svgElement: elm } of fetchSvgInBatches(src! )) {
if(elm.getAttribute("viewBox") && svgElement.current.getAttribute("viewBox") !== elm.getAttribute("viewBox") ) {
svgElement.current.setAttribute("viewBox", elm.getAttribute("viewBox"));
}
styleSvgPath(path);
setSvgPaths((prevPaths:SVGPathElement[]) => [...prevPaths, path]);
}
};
src && loadSvg();
}, [src]);
const host = useHost();
useEffect(()=> {
if(host.current?.shadowRoot) {
console.log("svg:host.current.shadowRoot", host.current.shadowRoot)
htmx.process(host.current.shadowRoot)
}
}, [host.current?.shadowRoot])
return html`
`;
}, {
props: {
src: { type: String, reflect: true },
alt: { type: String, reflect: false },
},
styles: css`
svg {
width: 100%;
height: 100%;
display: block;
z-index: 100;
},
:host {
display: inline-block;
width: 100%;
height: 100%;
background-color: blue;
}
/* CSS Animation for Handwriting Effect */
.draw-path {
animation: draw 1s ease-in-out forwards;
}
@keyframes draw {
from {
stroke-dashoffset: 100%; /* Start with the stroke completely hidden */
}
to {
stroke-dashoffset: 0%; /* Draw the stroke fully */
}
}
`
});
customElements.define("c-svg", SVG);