0

最近我拿起了一个项目,d3-flame-graph它根据另一个组件上定义的过滤器显示图表。我的问题是,在使用新参数搜索时,我似乎无法清理以前的图表,我想知道是否有人可以帮助我。基本上我现在拥有的是,当我第一次进入页面时,加载组件,然后我有我的图表,当我搜索新日期时,我有加载组件,但最重要的是我仍然有以前的图表

我想我可以使用flamegraph().destroy()const updateGraph什么也没发生

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
4

1 回答 1

0

首先,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
  )
  ...
}
于 2020-08-25T12:00:30.147 回答