91 lines
2.5 KiB
JavaScript
Raw Normal View History

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()