@mmorrii

Как убрать мерцание графика при перерисовке компонента?

У меня есть компонент с таблицей TablePanel, данные для которой я перебираю с помощью map. В одной из ячейки таблицы есть компонент с графиком LineChartWithoutLegend. Для графика использую библиотеку nivo.

Данные в wsResponseData обновляются ежесекундно и получается так, что при переборе этих данных, ячейки таблицы перерисовываются и вместе с ними компонент с графиком, из-за чего происходит эффект мерцания.

Пробовала выносить график вне map, такого мерцания нет. Также на странице есть другой линейный график у которого мерцания нет.

Подскажите что можно сделать, чтобы избежать такого поведения.

66732dd0d286a408321710.gif

export const TablePanel = () => {
    const wsResponseData = useContext(WsDataContext)
    const httpResponseData = useContext(HttpDataContext)

    return (
        <Table>
            <thead>
                //...
            </thead>
            <tbody>
                { httpResponseData.map(httpData => (
                    wsResponseData[httpData.Names[0]].slice(-1).map((data) => (
                        <tr key={data.keyId}>
                            //...
                            <td>{data.cpu_stats.online_cpus ?
                                <div style={{height: "46px", width: "140px"}}>
                                    <LineChartWithoutLegend containerName={data.name}/>
                                </div> :
                                "null"}
                            </td>
                        </tr>
                    ))
                ))}
            </tbody>
        </Table>
    )
}


export const LineChartWithoutLegend = ({ containerName }: { containerName: string }) => {
    const wsResponseData = useContext(WsDataContext)

    const chartDataRef = useRef<CoordsType[]>(initialLineChartData)

    useEffect(() => {
        const currentTime = getCurrentTime()
        const lastElemTime = chartDataRef.current[chartDataRef.current.length - 1]?.x

        if (currentTime === lastElemTime) return
        
        wsResponseData[containerName]?.slice(-1).map(wsData => {
            chartDataRef.current.push({x: currentTime, y: cpuUsage(wsData)})
        })

        if (chartDataRef.current.length > 30) {
            chartDataRef.current = chartDataRef.current?.slice(-30);
        }
    }, [containerName, wsResponseData]);

    return (
        <ResponsiveLineCanvas
            data={[
                {
                    id: "CPU usage monitoring",
                    data: chartDataRef.current,
                },
            ]}
            // другие настройки для графика
        />
    )
}
  • Вопрос задан
  • 172 просмотра
Пригласить эксперта
Ответы на вопрос 1
@odissey_nemo
Программист, ГИС-системы, растры, космоснимки
Логично сделать так, чтобы компоненты на экране не перерисовывались отдельно друг от друга на каждый чих , а перерисовывались после обновления всех данных в едином цикле. Со средой разработки и библиотеками графики указанного проекта не знаком, но принципы останутся общими, полагаю.
Следует либо останавливать вывод на время обновления, либо вывод организовать в какой то дополнительный буфер (в памяти?), с которого уже и обновлять на регулярной или событийной основе.
Например, при написании графических программ на Java через Swing, также и на Delphi и C# с их библиотеками, полезным оказалось иметь главный буфер в виде Bitmap размером с окно программы, который и использовался для обновления по произвольным событиям (скажем, периодическое обновление всего окна).
Вызвал все процедуры обновления и только тогда сказал repaint. Всё обновится с результирущего буфера, без всякого мигания.
Т.е. смысл в том, чтобы repaint вызывался не из каждого компонента отдельно и асинхронно, а один раз в подходящий момент, после гарантированного завершения всех срочных модификаций или даже на регулярной основе. Мерцания быть не должно.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы