React項目中使用HighCharts


  大家都知道BizCharts是基於react封裝的一套圖表工具,而HighCharts是基於jQuery的。但是由於本人對BizCharts甚是不熟,所以在react項目開發中選擇了HighCharts,在使用及對接數據的時候也是遇到了各種問題。

  下面簡單說下項目需求:首先是兩個網絡數據源,要求隨時間的變化網絡折線圖不斷更新,且當展示一定的數據點后開始折線圖從右往左平移。

  下面附上該組件所有代碼。

  

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import assign from 'object-assign'
import { autorun } from 'mobx'
import { observer } from 'mobx-react'

import Highcharts from 'highcharts'
import _ from 'lodash'
import ClassNames from 'classnames'

import './index.less'

@observer
class NetworkStatus extends Component {
  static propTypes = {
    style: PropTypes.object,
    onClose: PropTypes.func,
    localPings: PropTypes.array,
    fullPings: PropTypes.array,
  }

  static defaultProps = {
    style: {},
    onClose: _.noop,
    localPings: [],
    fullPings: [],
  }

  state = {
    stopFullPing: false,
    avgFullPingDelay: 0,
    lastFullPingDelay: 0,
    avgLocalPingDelay: 0,
    lastLocalPingDelay: 0,
  }

  componentDidMount() {
    const newChart = Highcharts.chart('chart_wrap', {
      chart: {
        type: 'spline',
        animation: false,
        marginRight: 10,
      },
      // 自定義數據列顏色,默認從第一個數據列起調用第一個顏色代碼,依次往后。
      colors: ['#f08500', '#9dc239'],
      // 不顯示右下角的版權信息
      credits: {
        enabled: false,
      },
      plotOptions: {
        series: {
          // 去掉鼠標懸浮到曲線上的默認線條加粗效果
          states: {
            hover: {
              enabled: false,
            },
          },
          // 禁用圖例點擊事件
          events: {
            legendItemClick(e) {
              return false
            },
          },
        },
      },
      // 是否使用國際標准時間
      time: {
        useUTC: false,
      },
      // 不顯示頭部標題
      title: {
        text: null,
      },
      xAxis: {
        type: 'datetime',
        // tickPixelInterval: 150,
        tickInterval: 60000,
        // labels: {
        //   step: 60,
        // },
      },
      yAxis: {
        title: {
          text: null,
        },
      },
      // 修改圖例樣式
      legend: {
        enabled: true,
        itemStyle: { color: '#4a4a4a', fontSize: '12px', fontWeight: 'normal' },
        itemHoverStyle: { cursor: 'normal' },
      },
      // 不顯示導出按鈕
      exporting: {
        enabled: false,
      },
      // 數據列具體數據設置
      series: [{
        // 表示使用哪個y軸
        yAxis: 0,
        name: 'Full Ping Delays',
        lineWidth: 1,
        // 不顯示曲線上的實心圓點
        marker: {
          enabled: false,
        },
        data: [],
      }, {
        yAxis: 0,
        name: 'Ping Delays',
        lineWidth: 1,
        // 不顯示曲線上的實心圓點
        marker: {
          enabled: false,
        },
        data: [],
      }],
    })

    this.chart = newChart

    this.initChartData(this.props.fullPings, this.props.localPings)

    // store中存儲的網絡數據每次更新時觸發以下代碼的執行,即動態往折線圖中添加點。
    this.cancelAutoRuns = [
      autorun(() => {
        if (!_.isEmpty(this.props.fullPings)) {
          const fullPingsArrayLength = this.props.fullPings.length
          let totalFullPingDelay = 0
          _.forEach(this.props.fullPings, (pings) => {
            totalFullPingDelay += pings.delay
          })
          this.setState({
            avgFullPingDelay: Math.round(totalFullPingDelay / fullPingsArrayLength),
            lastFullPingDelay: this.props.fullPings[fullPingsArrayLength - 1].delay,
          })
          const x = this.props.fullPings[fullPingsArrayLength - 1].time
          const y = this.props.fullPings[fullPingsArrayLength - 1].delay
          const seriesData = this.chart.series[0].data
          const shift = seriesData.length > 200
          if (x !== seriesData[seriesData.length - 1].x) {
            this.chart.series[0].addPoint([x, y], false, shift, false)
          }
          this.chart.redraw()
        }
      }),
      autorun(() => {
        if (!_.isEmpty(this.props.localPings)) {
          const localPingsArrayLength = this.props.localPings.length
          let totalLocalPingDelay = 0
          _.forEach(this.props.localPings, (pings) => {
            totalLocalPingDelay += pings.delay
          })
          this.setState({
            avgLocalPingDelay: Math.round(totalLocalPingDelay / localPingsArrayLength),
            lastLocalPingDelay: this.props.localPings[localPingsArrayLength - 1].delay,
          })
          const x = this.props.localPings[localPingsArrayLength - 1].time
          const y = this.props.localPings[localPingsArrayLength - 1].delay
          const seriesData = this.chart.series[1].data
          const shift = seriesData.length > 200
          if (x !== seriesData[seriesData.length - 1].x) {
            this.chart.series[1].addPoint([x, y], false, shift, false)
          }
          this.chart.redraw()
        }
      }),
    ]
  }

  componentWillUnmount() {
    this.chart.destroy()
    _.forEach(this.cancelAutoRuns, f => f())
  }

  chart = null

  cancelAutoRuns = null

  // 初始化localPings和fullPings折線圖數據
  initChartData = (fullPings, localPings) => {
    if (_.isEmpty(fullPings) || _.isEmpty(localPings)) {
      return
    }
    const fullPingsArrayLength = fullPings.length
    const localPingsArrayLength = localPings.length
    let totalFullPingDelay = 0
    let totalLocalPingDelay = 0

    // 初始化數據時,當store中存儲的網絡數據少於折線圖中定義的展示的點的個數(200)時就直接循環store中所有的數據,當store中數據大於點個數時,取store中后200個數據進行展示
    if (fullPingsArrayLength > 200 && localPingsArrayLength > 200) {
      const newFullPings = fullPings.slice(-200)
      const newLocalPings = localPings.slice(-200)
      this.cyclicPingsData(newFullPings, newLocalPings)
    } else {
      this.cyclicPingsData(fullPings, localPings)
    }

    _.forEach(fullPings, (pings) => {
      totalFullPingDelay += pings.delay
    })
    _.forEach(localPings, (pings) => {
      totalLocalPingDelay += pings.delay
    })
    this.setState({
      avgFullPingDelay: Math.round(totalFullPingDelay / fullPingsArrayLength),
      lastFullPingDelay: fullPings[fullPingsArrayLength - 1].delay,
      avgLocalPingDelay: Math.round(totalLocalPingDelay / localPingsArrayLength),
      lastLocalPingDelay: localPings[localPingsArrayLength - 1].delay,
    })
  }

  cyclicPingsData = (fullPings, localPings) => {
    _.forEach(fullPings, (pings) => {
      const x = pings.time
      const y = pings.delay
      this.chart.series[0].addPoint([x, y], false, false, true)
    })
    _.forEach(localPings, (pings) => {
      const x = pings.time
      const y = pings.delay
      this.chart.series[1].addPoint([x, y], false, false, true)
    })
    this.chart.redraw()
  }

  handleClickCloseBtn = () => {
    this.props.onClose()
  }

  handleClickChangeBtn = () => {
    const { stopFullPing } = this.state
    this.setState({ stopFullPing: !stopFullPing })

    // 點擊按鈕的同時隱藏或顯示 Full Ping Delays 折線
    if (!this.state.stopFullPing) {
      this.chart.series[0].hide()
    } else {
      this.chart.series[0].show()
    }
  }

  render() {
    const wrapStyles = assign({}, this.props.style)
    const hideFullPingTextClasses = ClassNames({
      hide: this.state.stopFullPing === true,
    })

    return (
      <div className="network_status_component_wrap" style={wrapStyles}>
        <div className="header">
          <span
            className="exit_icon"
            onClick={this.handleClickCloseBtn}
            role="button"
            tabIndex="0"
          />
        </div>
        <div className="container_wrap">
          <div className="text_information_wrap">
            <p className="text_one_p">
              <span>server: <span className="black_color">47.94.115.241:501</span></span>
              <span
                className="button_span"
                onClick={this.handleClickChangeBtn}
                role="button"
                tabIndex="0"
              >
                {
                  this.state.stopFullPing ? 'start full ping' : 'stop full ping'
                }
              </span>
              <span className="black_color">124.204.55.50 中國 北京 鵬博士/聯通</span>
            </p>
            <p id="text_two_p" className={hideFullPingTextClasses}>
              <span className="margin_right">avg full ping delay: <span>{this.state.avgFullPingDelay}</span> ms</span>
              <span>last full ping delay: <span>{this.state.lastFullPingDelay}</span> ms</span>
            </p>
            <p className="text_three_p">
              <span className="margin_right">avg ping delay: <span>{this.state.avgLocalPingDelay}</span> ms</span>
              <span>last ping delay: <span>{this.state.lastLocalPingDelay}</span> ms</span>
            </p>
          </div>
          <div id="chart_wrap" />

        </div>
      </div>
    )
  }
}

export default NetworkStatus

如下是效果圖:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM