加载新数据时删除 d3-flame-graph
Posted
技术标签:
【中文标题】加载新数据时删除 d3-flame-graph【英文标题】:Removing d3-flame-graph when loading new data 【发布时间】:2020-08-24 16:55:29 【问题描述】:最近我拿起了一个项目,上面有d3-flame-graph
,图表是根据另一个组件上定义的过滤器显示的。
我的问题是,在使用新参数搜索时,我似乎无法清理以前的图表,我想知道是否有人可以帮助我。基本上我现在拥有的是,当我第一次进入页面时,加载组件,然后我有我的图表,当我搜索新日期时,我有加载组件,但最重要的是我仍然有以前的图表
我想我可以在const updateGraph
上使用flamegraph().destroy()
,但什么也没发生
import React, FC, useEffect, useRef, useState, useCallback from 'react'
import useParams from 'react-router-dom'
import moment from 'moment'
import * as d3 from 'd3'
import flamegraph from 'd3-flame-graph'
import Filters, Filter from '../../../../../../components/Filters'
import getFlamegraph from '../../../../../../services/flamegraph'
import useQueryFilter from '../../../../../../hooks/filters'
import Flamegraphplaceholder from '../../../../../../components/Placeholders/Flamegraph'
import css from './flamegraph.module.css'
import ToastContainer,
useToastContainerMessage,
from '../../../../../../components/ToastContainer'
const defaultFilters =
startDate: moment().subtract(1, 'month'),
endDate: moment(),
text: '',
limit: 10,
const getOffSet = (divElement: htmlDivElement | null) =>
if (divElement !== null)
const padding = 100
const minGraphHeight = 450
// ensure that the graph has a min height
return Math.max(
window.innerHeight - divElement.offsetTop - padding,
minGraphHeight
)
else
const fallBackNavigationHeight = 300
return window.innerHeight - fallBackNavigationHeight
const Flamegraph: FC = () =>
const [queryFilters, setQueryFilters] = useQueryFilter(defaultFilters)
const [fetching, setFetching] = useState(false)
const [graphData, setGraphData] = useState()
const
messages: toastMessages,
addMessage: addMessageToContainer,
removeMessage: removeMessageFromContainer,
= useToastContainerMessage()
const flameContainerRef = useRef<HTMLDivElement | null>(null)
const flameRef = useRef<HTMLDivElement | null>(null)
const graphRef = useRef<any>()
const graphDataRef = useRef<any>()
const timerRef = useRef<any>()
const projectId, functionId = useParams()
let [sourceId, sourceLine] = ['', '']
if (functionId)
;[sourceId, sourceLine] = functionId.split(':')
const createGraph = () =>
if (flameContainerRef.current && flameRef.current)
graphRef.current = flamegraph()
.width(flameContainerRef.current.offsetWidth)
.height(getOffSet(flameRef.current))
.cellHeight(30)
.tooltip(false)
.setColorMapper(function(d, originalColor)
// Scale green component proportionally to box width (=> the wider the redder)
let greenHex = (192 - Math.round((d.x1 - d.x0) * 128)).toString(16)
return '#FF' + ('0' + greenHex).slice(-2) + '00'
)
const updateGraph = (newData: any) =>
setGraphData(newData)
graphDataRef.current = newData
if (graphRef.current)
if (newData === null)
graphRef.current.destroy()
graphRef.current = null
else
d3.select(flameRef.current)
.datum(newData)
.call(graphRef.current)
const fetchGraph = (filters: Filter) =>
setFetching(true)
getFlamegraph(
Number(projectId),
filters.startDate ? filters.startDate.unix() : 0,
filters.endDate ? filters.endDate.unix() : 0,
sourceId,
sourceLine
)
.then(graphData =>
if (!graphRef.current)
createGraph()
updateGraph(graphData)
)
.catch(( response ) =>
updateGraph(null)
if (response.data)
addMessageToContainer(response.data.message, true)
)
.finally(() =>
setFetching(false)
)
const onResize = useCallback(() =>
clearTimeout(timerRef.current)
timerRef.current = setTimeout(() =>
if (graphRef.current && flameContainerRef.current)
graphRef.current.width(flameContainerRef.current.offsetWidth)
d3.select(flameRef.current)
.datum(graphDataRef.current)
.call(graphRef.current)
, 500)
, [])
useEffect(() =>
fetchGraph(queryFilters)
window.addEventListener('resize', onResize)
return () =>
window.removeEventListener('resize', onResize)
// eslint-disable-next-line react-hooks/exhaustive-deps
, [])
const onChangeFilters = (filters: Filter) =>
setQueryFilters(filters)
fetchGraph(filters)
return (
<div className=css.host>
<Filters
defaultValues=queryFilters
searching=fetching
onSearch=onChangeFilters
/>
<div className=css.flameBox>
<div className=css.flameContainer ref=flameContainerRef>
<div ref=flameRef />
</div>
fetching || !graphData ? (
<FlamegraphPlaceholder loading=fetching />
) : null
</div>
<ToastContainer
messages=toastMessages
toastDismissed=removeMessageFromContainer
/>
</div>
)
export default Flamegraph
【问题讨论】:
【参考方案1】:首先,flamegraph()
创建flamegraph
的新实例,您需要使用graphref.current.destroy()
。其次,您不想在数据已经加载时销毁它,而是在它开始加载时销毁,对吗?因为那是需要时间的操作。
考虑以下几点:
const cleanGraph = () =>
if (graphref.current !== undefined)
graphref.current.destroy()
const fetchGraph = (filters: Filter) =>
setFetching(true)
cleanGraph()
getFlamegraph(
Number(projectId),
filters.startDate ? filters.startDate.unix() : 0,
filters.endDate ? filters.endDate.unix() : 0,
sourceId,
sourceLine
)
...
【讨论】:
以上是关于加载新数据时删除 d3-flame-graph的主要内容,如果未能解决你的问题,请参考以下文章
删除对象后重新加载 UICollectionViewController?