I'm trying to create a word cloud using the @visx/wordCloud library in my React application. However, the rendering time is very slow (about 10 seconds), and I need to create new word clouds on the fly as part of an interactive dashboard, so this delay is problematic.
The sample uses 1000 words and this is the code I am using right now.
import React, { useState, useEffect, useMemo, useCallback, useRef, useLayoutEffect } from 'react';
import { Group } from '@visx/group';
import { Wordcloud } from '@visx/wordcloud';
import { Text } from '@visx/text';
interface LinearScale {
domain: [number, number];
range: [number, number];
}
function createLinearScale({ domain, range }: LinearScale) {
const [domainMin, domainMax] = domain;
const [rangeMin, rangeMax] = range;
const slope = (rangeMax - rangeMin) / (domainMax - domainMin);
const intercept = rangeMax - slope * domainMax;
return (x: number) => slope * x + intercept;
}
type Word = {
text: string;
value: number;
};
import data from '../../../data/sample_data/total_wcloud_sample.json'
const randomwords =data
function getRandomRotation() {
return Math.random() < 0.5 ? 90 : 0; // 50% of words will be rotated by 90 degrees
}
const WordcloudExample = () => {
const [words, setWords] = useState<Word[]>([]);
const width = 800;
const height = 800;
useEffect(() => {
setWords(randomwords);
}, []);
const weightScale = useMemo(() =>
createLinearScale({
domain: [Math.min(...words.map((w) => w.value)), Math.max(...words.map((w) => w.value))],
range: [10, 70],
}),
[words]
);
const fontSize = useCallback((word: Word) => weightScale(word.value), []);
return (
<svg width={width} height={height}>
<rect x={0} y={0} width={width} height={height} fill="#f8f8f8" />
<Group >
<Wordcloud
words={words}
fontSize={fontSize}
width={width}
height={height}
random={getRandomRotation}
spiral={'rectangular'}
//10% should be rotated, 90% should have a rotation of 0
rotate={ getRandomRotation }
>
{(cloudWords) =>
cloudWords.map((w, i) => (
<Text
key={w.text}
textAnchor={'middle'}
transform={`translate(${w.x}, ${w.y}) rotate(${w.rotate})`}
fontSize={w.size}
fontFamily={w.font}
fontWeight={w.weight}
//random color for each word
fill={`hsl(${Math.random() * 360}, 100%, 50%)`}
>
{w.text}
</Text>
))
}
</Wordcloud>
</Group>
</svg>
);
};
export default WordcloudExample;
I've tried to optimize the code by using useMemo and useCallback, but it doesn't seem to have much of an effect. I've also created a sample on Codesandbox to show the problem. However, for some reason, the sample on Codesandbox is much faster.
Does anyone have any suggestions for optimizing the rendering time of @visx/wordCloud, or any other word cloud libraries that might be faster? I appreciate any help or advice you can offer. Thank you!