kappys1/react-arc-text

ref (use DOM manipulation) is not Component's philosophy

Opened this issue · 1 comments

https://en.reactjs.org/docs/refs-and-the-dom.html

WebComponent is Js encapsulated HTML.
No DOM manupulation.

Got this
image

Configuration

<ReactArcText cssOverride={{}} dir="up" fontSize={20} isHeightForced={true}  isWidthForced={true} lineHeight={1} text="Ukraine" totalSize={{height:300, width:300}} />

Code more friendly with React !

export function arrayByNum(num: number) { return Array.from(new Array(num)).map((el, i) => { if (el) { }; return i.toString() }) }
function getRect(fontSize: number): IRect { return { height: fontSize, width: fontSize } }
const radiansPerDegree = Math.PI / 180
const degreesPerRadian = 180 / Math.PI
function chord(r: number, θ: any) { return 2 * r * Math.sin(degreesToRadians(θ / 2)) };
function radiansToDegrees(angleInDegrees: number) { return angleInDegrees * degreesPerRadian };
function degreesToRadians(angleInDegrees: number) { return angleInDegrees * radiansPerDegree };
function sagitta(r: number, θ: any) { return r * (1 - Math.cos(degreesToRadians(θ / 2))) };
function getLetterRotations(metrics: IRect[], r: number) { return metrics.reduce((data, { width }) => { const rotation = radiansToDegrees(width / r); return { θ: data.θ + rotation, rotations: data.rotations.concat([data.θ + rotation / 2]) } }, { θ: 0, rotations: [] }) }

function convertDir(dir: "down" | "up") { return dir === "up" ? 1 : -1 }
export class ReactArcText extends Component<{
    text: string,
    cssOverride: CSSProperties,
    // arc: number
    fontSize: number,
    totalSize: { width: number, height: number }
    lineHeight: number
    isWidthForced: boolean
    isHeightForced: boolean
    dir: "up" | "down"
}, any>{
    render() {
        const { dir, cssOverride, fontSize, isHeightForced, isWidthForced, lineHeight, text, totalSize } = this.props;
        const { height, width } = totalSize

        const radius = width / Math.PI / 2 + lineHeight;
        const matrix = arrayByNum(text.length).map(() => { return getRect(fontSize) })
        const innerRadius = radius - lineHeight
        const { rotations, θ } = getLetterRotations(matrix, innerRadius)

        return <div className="react-arc-text" style={{
            ...cssOverride, position: "relative",
            width: isWidthForced ? `${chord(radius, Math.min(180, θ)) / fontSize}em` : "unset",
            height: isHeightForced ? `${(θ > 180
                ? sagitta(radius, θ)
                : sagitta(innerRadius, θ) + lineHeight)
                / fontSize
                }em` : "unset"
        }}>
            {text.split("").map((letter, i) => {
                const rotate = (θ * -0.5 + rotations[i]) * convertDir(dir)
                const ElWidth = matrix.length < i + 1 ? undefined : matrix[i].width;
                const translateX = ElWidth === undefined ? 0 : ElWidth / fontSize
                return <p style={{
                    transform: `translateX(${translateX}em) rotate(${rotate}deg)`, position: "absolute",
                    bottom: dir === "down" ? '0' : 'auto',
                    left: "50%",
                    transformOrigin: `center ${(dir === "down" ? -radius + lineHeight : radius) / fontSize}em`
                }}>{letter}</p>
            })}
        </div>
    }
}

If you can impoove it ( configuration for arc value ).... there is no DOM but expect fontSize is the width of each letter (you can add spaceLetter otherwise ) better than DOM .