import tinygradient from "tinygradient" // An internal function to help with easily creating SVG elements with an object of attributes export const svgElem = (type, attrs) => { const elem = document.createElementNS("http://www.w3.org/2000/svg", type), attributes = Object.keys(attrs) for (let i = 0; i < attributes.length; i++) { const attr = attributes[i] elem.setAttribute(attr, attrs[attr]) } return elem } // An internal function to help with the repetition of adding fill, stroke, and stroke-width attributes export const styleAttrs = ( fill, stroke, strokeWidth, progress, animation ) => { const determineColor = (type, progress) => typeof type === "string" ? type : tinygradient(type).rgbAt(progress) const attrs = {} if (stroke) { attrs["stroke"] = determineColor(stroke, progress) attrs["stroke-width"] = strokeWidth } if (fill) { attrs["fill"] = determineColor(fill, progress) } if (animation?.name) { // TODO: add animation-direction support const duration = animation.duration || 5 attrs["style"] = ` animation-name: ${animation?.name}; animation-delay: ${progress * duration - duration}s; animation-duration: ${duration}s; animation-iteration-count: infinite; animation-timing-function: linear;` } return attrs } // An internal function to convert any array of samples into a "d" attribute to be passed to an SVG path export const segmentToD = (samples) => { let d = "" for (let i = 0; i < samples.length; i++) { const { x, y } = samples[i], prevSample = i === 0 ? null : samples[i - 1] if (i === 0 && i !== samples.length - 1) { d += `M${x},${y}` } else if (x !== prevSample.x && y !== prevSample.y) { d += `L${x},${y}` } else if (x !== prevSample.x) { d += `H${x}` } else if (y !== prevSample.y) { d += `V${y}` } if (i === samples.length - 1) { d += "Z" } } return d } // An internal function for getting the colors of a segment, we need to get middle most sample (sorted by progress along the path) export const getMiddleSample = (samples) => { const sortedSamples = [...samples].sort((a, b) => a.progress - b.progress) return sortedSamples[(sortedSamples.length / 2) | 0] } // An internal function for converting any D3 selection or DOM-like element into a DOM node export const convertPathToNode = (path) => path instanceof Element || path instanceof HTMLDocument ? path : path.node()