rrag / react-stockcharts

Highly customizable stock charts with ReactJS and d3
http://rrag.github.io/react-stockcharts
MIT License
3.84k stars 956 forks source link

InteractiveYCordinates disappears on mouse enter and mouse click events #824

Open patrickcook28 opened 10 months ago

patrickcook28 commented 10 months ago

Whenever the mouse enters the chart the alert disappears. I am using the CandleStickChartWithInteractiveYCoordinate example.

The alert then re-renders a little later. If I hover over the alert it doesnt not view as selectable. I also cannot click and drag the alert to change its position. If I click the alert it just disappears. The this.state still shows the yCoordinateList_1 has my alert.

Setting mouseEvent prop to false fixes the mouse enter issue. But when mouse leaves chart the alert then disappears again

class CandlestickChart extends React.Component {
  constructor(props) {
    super(props);
    this.saveNode = this.saveNode.bind(this);
    this.resetYDomain = this.resetYDomain.bind(this);

    this.saveInteractiveNodes = saveInteractiveNodes.bind(this);
    this.getInteractiveNodes = getInteractiveNodes.bind(this);

    this.onDragComplete = this.onDragComplete.bind(this);
    this.handleSelection = this.handleSelection.bind(this);
    this.handleChoosePosition = this.handleChoosePosition.bind(this);
    this.onDragComplete = this.onDragComplete.bind(this);
    this.onDelete = this.onDelete.bind(this);

    this.state = {
      enableInteractiveObject: false,
      yCoordinateList_1: [
        {
          ...InteractiveYCoordinate.defaultProps.defaultPriceCoordinate,
          yValue: 4523.0,
          id: 'stopLoss',
          draggable: true,
        },
      ],
      showModal: false,
      alertToEdit: {}
    };
  }

  saveNode(node) {
    this.node = node;
  }

  resetYDomain() {
    this.node.resetYDomain();
  }

  onDragComplete(yCoordinateList, moreProps, draggedAlert) {
    // this gets called on drag complete of drawing object
    const { id: chartId } = moreProps.chartConfig;

    const key = `yCoordinateList_${chartId}`;
    const alertDragged = draggedAlert != null;

    this.setState({
      enableInteractiveObject: false,
      [key]: yCoordinateList,
      showModal: alertDragged,
      alertToEdit: {
        alert: draggedAlert,
        chartId,
      },
      originalAlertList: this.state[key],
    });
  }

  handleSelection(interactives, moreProps, e) {
    console.log("HANDLE SELECTION", interactives, moreProps, e)
    if (this.state.enableInteractiveObject) {
      const independentCharts = moreProps.currentCharts.filter(d => d !== 2);
      if (independentCharts.length > 0) {
        const first = head(independentCharts);

        const morePropsForChart = getMorePropsForChart(moreProps, first);
        const {
          mouseXY: [, mouseY],
          chartConfig: { yScale },
        } = morePropsForChart;

        const yValue = round(yScale.invert(mouseY), 2);
        const newAlert = {
          ...InteractiveYCoordinate.defaultProps.defaultPriceCoordinate,
          yValue,
          id: 'newAlert1'
        };
        this.handleChoosePosition(newAlert, morePropsForChart, e);
      }
    } else {
      // const state = toObject(interactives, each => {
      //   return [
      //     `yCoordinateList_${each.chartId}`,
      //     each.objects,
      //   ];
      // });
      // this.setState(state);
    }
  }

  handleChoosePosition(alert, moreProps) {
    const { id: chartId } = moreProps.chartConfig;
    this.setState({
      [`yCoordinateList_${chartId}`]: [
        ...this.state[`yCoordinateList_${chartId}`],
        alert
      ],
      enableInteractiveObject: false,
    });
  }

  onDelete(yCoordinate, moreProps) {
    this.setState(state => {
      const chartId = moreProps.chartConfig.id;
      const key = `yCoordinateList_${chartId}`;

      const list = state[key];
      return {
        [key]: list.filter(d => d.id !== yCoordinate.id)
      };
    });
  }

  render() {
    const greenColor = "#60BC92";
    const redColor = "#C83A57";
    const { chartData } = this.props;
    const { mouseMoveEvent, panEvent, zoomEvent, zoomAnchor } = this.props;
    const { clamp } = this.props;

    const height = 800;
    const width = 800;

    const margin = {left: 70, right: 70, top: 50, bottom: 30};
    const gridHeight = height - margin.top - margin.bottom;
    const gridWidth = width - margin.left - margin.right;

    const showGrid = true;
    const yGrid = showGrid ? {
      innerTickSize: -1 * gridWidth,
      tickStrokeDasharray: 'Solid',
      tickStrokeOpacity: 0.2,
      tickStrokeWidth: 1
    } : {};
    const xGrid = showGrid ? {
      innerTickSize: -1 * gridHeight,
      tickStrokeDasharray: 'Solid',
      tickStrokeOpacity: 0.2,
      tickStrokeWidth: 1
    } : {};

    const xScaleProvider = discontinuousTimeScaleProvider.inputDateAccessor(d => d.date);
    const {
      data,
      xScale,
      xAccessor,
      displayXAccessor,
    } = xScaleProvider(chartData);

    const start = xAccessor(data[0]);
    const end = xAccessor(last(data));
    const xExtents = [start, end];

    console.log(this.state)
    return (
      <ChartCanvas
        ref={this.saveNode}
        height={height}
        width={width}
        ratio={1}
        margin={margin}
        type={'hybrid'}
        panEvent={panEvent}
        zoomEvent={zoomEvent}
        mouseMoveEvent={false}
        clamp={clamp}
        zoomAnchor={zoomAnchor}
        seriesName="MES"
        data={data}
        xScale={xScale}
        xAccessor={xAccessor}
        displayXAccessor={displayXAccessor}
        xExtents={xExtents}
      >
        <Chart
          id={1}
          height={400}
          yExtents={[(d) => [d.high, d.low]]}
          padding={{ top: 10, bottom: 40 }}
        >
          <XAxis
            axisAt="bottom"
            orient="bottom"
            tickStroke="#FFFFFF"
            {...xGrid}
          />
          <YAxis
            axisAt="right"
            orient="right"
            tickStroke="#FFFFFF"
            tickFormat={format(".2f")}
            {...yGrid}
          />

          <MouseCoordinateY
            at="right"
            orient="right"
            displayFormat={format(".2f")} />

          <CandlestickSeries
            stroke={d => d.close > d.open ? greenColor : redColor}
            wickStroke={d => d.close > d.open ? greenColor : redColor}
            fill={d => d.close > d.open ? "rgba(0, 0, 0, 0.0)" : redColor}
            opacity={1}
          />

          <InteractiveYCoordinate
            ref={this.saveInteractiveNodes("InteractiveYCoordinate", 1)}
            enabled={this.state.enableInteractiveObject}
            onDragComplete={this.onDragComplete}
            onDelete={this.onDelete}
            yCoordinateList={this.state.yCoordinateList_1}
          />

          <ClickCallback
            onMouseMove={(moreProps, e) => {
              console.log("onMouseMove", moreProps, e);
            }}
            onMouseDown={(moreProps, e) => {
              console.log("onMouseDown", moreProps, e);
            }}
            onClick={(moreProps, e) => {
              console.log("onClick", moreProps, e);
            }}
            onDoubleClick={(moreProps, e) => {
              console.log("onDoubleClick", moreProps, e);
            }}
            onContextMenu={(moreProps, e) => {
              console.log("onContextMenu", moreProps, e);
            }}
            onPan={(moreProps, e) => {
              console.log("onPan", moreProps, e);
            }}
            onPanEnd={(moreProps, e) => {
              console.log("onPanEnd", moreProps, e);
            }}
          />
        </Chart>
        <DrawingObjectSelector
          enabled
          getInteractiveNodes={this.getInteractiveNodes}
          drawingObjectMap={{
            InteractiveYCoordinate: "yCoordinateList"
          }}
          onSelect={this.handleSelection}
        />
        <Chart
          id={2}
          height={150}
          yExtents={[(d) => d.volume]}
          origin={(w, h) => [0, h - 300]}
        >
          <YAxis
            axisAt="right"
            orient="right"
            ticks={5}
            tickFormat={format(".2s")}
            zoomEnabled={zoomEvent}
            tickStroke="#FFFFFF"
          />

          <BarSeries
            yAccessor={(d) => d.volume}
            fill={(d) => (d.close > d.open ? greenColor : redColor)}
          />
        </Chart>
        <CrossHairCursor />
      </ChartCanvas>
    );
  }
}