【问题标题】:Removing d3-flame-graph when loading new data加载新数据时删除 d3-flame-graph
【发布时间】: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

【问题讨论】:

    标签: reactjs d3.js 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
      )
      ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-29
      • 1970-01-01
      • 1970-01-01
      • 2016-11-14
      • 1970-01-01
      • 2021-07-20
      • 2011-04-27
      • 2017-09-16
      相关资源
      最近更新 更多