React highchart: общая всплывающая подсказка на той же диаграмме и в другой диаграмме

Я использую для проекта response-highchart. И отображение двух диаграмм: 1) Линейная диаграмма с данными двух серий, она отобразит две линии на одной диаграмме. 2) Гистограмма или столбчатая диаграмма.

Теперь, когда я нахожу указатель на точку, всплывающая подсказка должна отображаться как в строках 1-го графика, так и в столбчатой ​​диаграмме. Ось X - это дата и время. Он должен быть активным в обеих строках следующим образом:

введите здесь описание изображения

В react-highchart я использовал атрибут shared: true, но он не делает активными обе строки.

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

И есть ли способ сделать активной всплывающую подсказку другого графика?

ИЗМЕНИТЬ

После предложения я проверял synchronized-charts в highcharts, но пример кода был в jQuery мне нужно в react-highcharts. Тем не менее я попытался преобразовать код, чтобы он реагировал, и сделал следующее:

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
};

После обратного вызова отрисовки диаграммы:

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

Обработка перемещения и синхронизации мыши

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' },
          );
        }
      }
    });
  }
}

Теперь, когда я нахожу указатель мыши на точку, появляется ошибка:

введите здесь описание изображения

Но каким-то образом это сработало для второй диаграммы. Если я наведу курсор на точку второй диаграммы, на обеих диаграммах появится всплывающая подсказка. Не работает для первого графика. Плюс первый график состоит из двух серий. Я приближаюсь к решению.

РЕДАКТИРОВАТЬ 2: Решение. Я выяснил, что вызывает синхронизацию всплывающих подсказок только при наведении курсора на вторую диаграмму. Это произошло из-за ошибки консоли, которая нарушала код (цикл For внутри handleMouseMove()). Таким образом, после помещения этой ошибки в try catch проблема была решена.

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

Не лучший способ, но работает. Единственная проблема сейчас в том, что первая диаграмма имеет две линии серий (проверьте изображение выше), и только первая получает активный кружок, а не вторая.

РЕДАКТИРОВАТЬ 3. Решение для выделения нескольких серий.

Прочитав код, я нашел эту строку, из-за которой только первая серия выделяла точку:

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

эта линия занимает только первую серию. Плохой код. Должен быть:

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

Единственная проблема - теперь эта попытка поймать без получения Can not read property category of undefined.


person Rahul Sagore    schedule 08.11.2018    source источник
comment
Для этого требуются синхронизированные диаграммы, проверьте этот пример highcharts.com/demo/synchronized-charts.   -  person Wojciech Chmiel    schedule 08.11.2018
comment
@WojciechChmiel Спасибо за правильный вариант, я попробовал и обновил вопрос. Есть ли на это пример реакции?   -  person Rahul Sagore    schedule 12.11.2018
comment
@WojciechChmiel Каким-то образом это сработало для второй диаграммы. Если я наведу курсор на вторую точку диаграммы, появится всплывающая подсказка на обеих диаграммах. Не работает для первого графика. Плюс первый график состоит из двух серий. Я приближаюсь к решению.   -  person Rahul Sagore    schedule 12.11.2018


Ответы (1)


Я рекомендую вам использовать highcharts-react-official обертку. Ниже вы можете найти пример синхронизированных графиков:

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"));

Живая демонстрация: https://codesandbox.io/s/jl8mrq2m53

person ppotaczek    schedule 13.11.2018
comment
Это работает, но моя первая диаграмма имеет две серии линий, и я хочу добавить кружок наведения на обеих линиях, если какая-либо из них зависает, проверьте снимок экрана, который я добавил в вопрос. Только наведенная линия становится активным кружком на точке. - person Rahul Sagore; 04.12.2018
comment
И при вызове функции point.highlight(e); выдает ошибку консоли TypeError: Cannot read property 'category' of undefined. - person Rahul Sagore; 04.12.2018
comment
Разобрался, эта строка point = chart.series[0].searchPoint(event, true); взяла только первую серию. После зацикливания он исправил проблему. - person Rahul Sagore; 04.12.2018