React highchart:相同和不同图表中的共享工具提示 [英] React highchart: Shared tooltip in same and different chart

查看:102
本文介绍了React highchart:相同和不同图表中的共享工具提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为项目使用react-highchart.并显示两个图表:1)带有2个系列数据的折线图,它将在同一张图表上绘制两条线.2)条形图或柱形图.

现在,当我将鼠标悬停在一个点上时,它应该在第一张图表和柱状图中的两条线上都启用工具提示.X轴是日期时间.它应该在两行上都这样激活点:

react-highchart 中,我使用了 shared:true 属性,但是它没有使两条线都处于活动状态.

 工具提示:{已启用:true,useHTML:是的,共享:是的,backgroundColor:'rgba(255,255,255,1)',borderRadius:3,形状:矩形"} 

有没有办法使另一个图表的工具提示也处于活动状态?

编辑

在提出建议后,我在高图中检查了

但是以某种方式,它适用于第二张图表,如果我将鼠标悬停在第二张图表上,它将在两个图表上显示工具提示.不适用于第一个图表.再加上第一个图表有两个系列.我正在接近解决方案.

解决方案我发现,仅当将鼠标悬停在第二张图表上时,才导致工具提示同步的原因.这是由于该控制台错误所致,它破坏了代码( handleMouseMove()中的For循环).因此,将错误放入 try catch 后,它可以解决此问题.

  if(point){尝试 {point.highlight(e);} catch(err){//经过;}} 

不是最好的方法,但是它可以工作.现在唯一的问题是,第一个图表具有两条系列线(请参见上图),只有第一个具有活动圆,而不是第二个.

突出显示多个系列的解决方案.

阅读代码后,我发现这行代码,这只是导致第一个系列突出显示点:

  point = chart.series [0] .searchPoint(event,true) 

这条线仅是第一个系列.错误的代码.应该是:

  chart.series.forEach(series => {const point = series.searchPoint(event,true);如果(点){尝试 {point.highlight(e);} catch(err){//经过;}}}); 

现在唯一的问题是此try catch,但没有得到无法读取未定义的属性类别.

解决方案

我建议您使用 highcharts-react-official 包装器.您可以在下面找到同步图表的示例:

  import从反应"中反应;从"react-dom"导入{render};//导入Highcharts从"highcharts/highstock"中导入Highcharts;//从"./HighchartsReact.min.js"导入HighchartsReact;从"highcharts-react-official"导入HighchartsReact;(函数(H){H.Pointer.prototype.reset = function(){返回未定义;};/***通过显示工具提示,设置悬停状态并绘制十字线来突出显示一个点*/H.Point.prototype.highlight = function(event){事件= this.series.chart.pointer.normalize(事件);this.onMouseOver();//显示悬停标记this.series.chart.tooltip.refresh(this);//显示工具提示this.series.chart.xAxis [0] .drawCrosshair(event,this);//显示十字准线};H.syncExtremes = function(e){var thisChart = this.chart;如果(e.trigger!=="syncExtremes"){//防止反馈循环Highcharts.each(Highcharts.charts,function(chart){if(图表&&图表!== thisChart){如果(chart.xAxis [0] .setExtremes){//更新时为nullchart.xAxis [0] .setExtremes(e.min,e.max,undefined,false,{触发条件:"syncExtremes"});}}});}};})(Highcharts);App类扩展了React.Component {构造函数(道具){超级(道具);this.state = {选项: {图表: {类型:行",zoomType:"x",平移:正确,panKey:"shift"},xAxis:{事件:{setExtremes:function(e){Highcharts.syncExtremes(e);}}},系列: [{数据: [29.9,71.5,106.4,129.2,144.0,176.0,135.6,148.5,216.4,194.1,95.6,54.4]}]},选项2:{图表: {zoomType:"x"},系列: [{数据:[1、2、3、4、5、6、7、8、9、10、11、12]}],xAxis:{事件:{setExtremes:function(e){Highcharts.syncExtremes(e);}}}}};}componentDidMount(){["mousemove","touchmove","touchstart"].forEach(function(eventType){文档.getElementById(容器").addEventListener(eventType,function(e){var chart,point,i,event;对于(i = 0; i< Highcharts.charts.length; i = i + 1){图表= Highcharts.charts [i];如果(图表){//在图表中查找坐标事件= chart.pointer.normalize(e);//获取悬停点点= chart.series [0] .searchPoint(event,true);如果(点){point.highlight(e);}}}});});}inputChange(e){this.setState({选项: {系列:[{数据:[1,1,1]},{数据:[2,2,2]}]}});}使成为() {返回 (< div id ="container">< Highcharts反应constructorType = {图表"}highcharts = {Highcharts}选项= {this.state.options}/>< Highcharts反应constructorType = {图表"}highcharts = {Highcharts}选项= {this.state.options2}/></div>);}}render(< App/> ;, document.getElementById("root")); 

实时演示: https://codesandbox.io/s/jl8mrq2m53

I am using react-highchart for a project. And displaying two charts: 1) Line Chart with 2 series data, it will render two lines on same chart. 2) Bar or Column Chart.

Now when I hover over a point it should enable tooltip on both lines in 1st chart and in column chart as well. X-axis is datetime. It should active point on both lines like this:

In react-highchart, I have used shared: true attribute, but it is not making both lines active.

tooltip: {
  enabled: true,
  useHTML: true,
  shared: true,
  backgroundColor: 'rgba(255,255,255,1)',
  borderRadius: 3,
  shape: 'rectangle'
}

And is there a way to make another chart's tooltip active as well?

EDIT

After a suggestion, I was checking synchronized-charts in highcharts, but the code example was in jQuery, I need it in react-highcharts. Still I tried to convert the code to react and did this:

import ReactHighcharts from 'react-highcharts/ReactHighcharts';

/**
 * Override the reset function, we don't need to hide the tooltips and
 * crosshairs.
*/
ReactHighcharts.Highcharts.Pointer.prototype.reset = function reset() {
 return undefined;
};

ReactHighcharts.Highcharts.Point.prototype.highlight = function highlight(event) {
 event = this.series.chart.pointer.normalize(event);
 this.onMouseOver(); // Show the hover marker
 this.series.chart.tooltip.refresh(this); // Show the tooltip
 this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the 
 crosshair
};

After chart render callback:

['mousemove', 'touchmove', 'touchstart'].forEach(eventType => {
  const container = document.getElementById('tab__charts');
  container.removeEventListener(eventType, this.handleMouseMove);
  container.addEventListener(eventType, this.handleMouseMove);
});

Handle Mouse move and syncExtreme:

handleMouseMove(e) {
  for (let i = 0; i < ReactHighcharts.Highcharts.charts.length; i += 1) {
    const chart = ReactHighcharts.Highcharts.charts[i];
    if (chart) {
      // Find coordinates within the chart
      const event = chart.pointer.normalize(e);
      // Get the hovered point
      const point = chart.series[0].searchPoint(event, true);

      if (point) {
        point.highlight(e);
      }
    }
  }
}

syncExtremes(e) {
  const thisChart = this.chart;

  if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
    ReactHighcharts.Highcharts.each(ReactHighcharts.Highcharts.charts, (chart) => {
      if (chart !== thisChart) {
        if (chart.xAxis[0].setExtremes) { // It is null while updating
          chart.xAxis[0].setExtremes(
            e.min,
            e.max,
            undefined,
            false,
            { trigger: 'syncExtremes' },
          );
        }
      }
    });
  }
}

Now when I hover over the the point it is giving error:

But Somehow It worked for second chart, If I hover over second chart point, it is showing tooltip on both chart. Not working for first chart. Plus first chart has two series. I am getting closer to solution.

EDIT 2: Solution I figured out that what was causing Tooltips to be synchronised only if hover over second Chart. It was due to that console error, which was breaking the code (For loop inside handleMouseMove()). So after putting that error into try catch, it fixed the problem.

 if (point) {
   try {
     point.highlight(e);
   } catch (err) {
      // pass;
   }
 }

Not the best way, but it works. The only problem now is, first chart has two Series line (Check the above image), and only first one getting active circle, not the second one.

EDIT 3: Solution for Highlighting Multiple series.

After reading the code, I found this line, whhich was causing only first series to highlight point:

point = chart.series[0].searchPoint(event, true)

this line is only taking first series. Bad code. It should be:

chart.series.forEach(series => {
    const point = series.searchPoint(event, true);
    if (point) {
        try {
            point.highlight(e);
        } catch (err) {
            // pass;
        }
    }
});

The only issue is now this try catch, without it getting Can not read property category of undefined.

解决方案

I recommend you to use highcharts-react-official wrapper. Below you can find an example of synchronized charts:

import React from "react";
import { render } from "react-dom";
// Import Highcharts
import Highcharts from "highcharts/highstock";
//import HighchartsReact from "./HighchartsReact.min.js";
import HighchartsReact from "highcharts-react-official";

(function(H) {
  H.Pointer.prototype.reset = function() {
    return undefined;
  };

  /**
   * Highlight a point by showing tooltip, setting hover state and draw crosshair
   */
  H.Point.prototype.highlight = function(event) {
    event = this.series.chart.pointer.normalize(event);
    this.onMouseOver(); // Show the hover marker
    this.series.chart.tooltip.refresh(this); // Show the tooltip
    this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
  };

  H.syncExtremes = function(e) {
    var thisChart = this.chart;

    if (e.trigger !== "syncExtremes") {
      // Prevent feedback loop
      Highcharts.each(Highcharts.charts, function(chart) {
        if (chart && chart !== thisChart) {
          if (chart.xAxis[0].setExtremes) {
            // It is null while updating
            chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {
              trigger: "syncExtremes"
            });
          }
        }
      });
    }
  };
})(Highcharts);

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      options: {
        chart: {
          type: "line",
          zoomType: "x",
          panning: true,
          panKey: "shift"
        },
        xAxis: {
          events: {
            setExtremes: function(e) {
              Highcharts.syncExtremes(e);
            }
          }
        },
        series: [
          {
            data: [
              29.9,
              71.5,
              106.4,
              129.2,
              144.0,
              176.0,
              135.6,
              148.5,
              216.4,
              194.1,
              95.6,
              54.4
            ]
          }
        ]
      },
      options2: {
        chart: {
          zoomType: "x"
        },
        series: [
          {
            data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
          }
        ],
        xAxis: {
          events: {
            setExtremes: function(e) {
              Highcharts.syncExtremes(e);
            }
          }
        }
      }
    };
  }

  componentDidMount() {
    ["mousemove", "touchmove", "touchstart"].forEach(function(eventType) {
      document
        .getElementById("container")
        .addEventListener(eventType, function(e) {
          var chart, point, i, event;

          for (i = 0; i < Highcharts.charts.length; i = i + 1) {
            chart = Highcharts.charts[i];
            if (chart) {
              // Find coordinates within the chart
              event = chart.pointer.normalize(e);
              // Get the hovered point
              point = chart.series[0].searchPoint(event, true);

              if (point) {
                point.highlight(e);
              }
            }
          }
        });
    });
  }

  inputChange(e) {
    this.setState({
      options: {
        series: [{ data: [1, 1, 1] }, { data: [2, 2, 2] }]
      }
    });
  }

  render() {
    return (
      <div id="container">
        <HighchartsReact
          constructorType={"chart"}
          highcharts={Highcharts}
          options={this.state.options}
        />
        <HighchartsReact
          constructorType={"chart"}
          highcharts={Highcharts}
          options={this.state.options2}
        />
      </div>
    );
  }
}

render(<App />, document.getElementById("root"));

Live demo: https://codesandbox.io/s/jl8mrq2m53

这篇关于React highchart:相同和不同图表中的共享工具提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆