2

I am wanting to add the drag and drop functionality to plotlines along the yAxis since my chart is inverted.

I have found several questions that seem to get me so close to the solution, but I have not been able to implement the solutions wile using the React-Highcharts package.

both solutions spell out a very workable solution. My problem is translating solutions into the React-Highchartscomponent.

This is a JSFiddle with a slimed down version of my chart.

Below is my current config for yAxis

  config.yaxis = {
   title: 'Times',
   descrition: 'Times within a 24 hour day.',
   endOnTick: false,
   opposite: true,
   min: Date.UTC(0,0,0,0,0,0),
   max: Date.UTC(0,0,0,24,30,0),
   plotLines: [{
                   value: Date.UTC(0,0,0,6,0,0),
                   id: 'plotLineId',
                   color: colorObj.open,
                   dashStyle: 'shortdash',
                   width: 2,
                   zIndex: 4,
                   onDragStart: function (new_value) {
                    $("#x_value").text(new_value + ' (Not changed yet)');
                    },
                   onDragChange: function (new_value) {
                        $("#x_value").text(new_value + ' (Dragging)');
                    },
                   onDragFinish: function (new_value) {
                        $("#x_value").text(new_value);
                    }
               }, {
                   value: Date.UTC(0,0,0,21,0,0),
                   id: 'plotLineId',
                   color: colorObj.close,
                   dashStyle: 'shortdash',
                   width: 2,
                   zIndex: 4,
                   onDragStart: function (new_value) {
                        $("#x_value").text(new_value + ' (Not changed yet)');
                    },
                   onDragChange: function (new_value) {
                        $("#x_value").text(new_value + ' (Dragging)');
                    },
                   onDragFinish: function (new_value) {
                        $("#x_value").text(new_value);
                    }
               }],
   type: 'datetime',
   dateTimeLabelFormats: {

     minute: '%l:%M%p',
     hour: '%l %p',
     day: '%l %p'

   },
   events: {
     mouseOver: function (e) {
       console.log('mouseOver - ', e);
     }
   }
 }

and what I have in the file for the ReactHighcharts component

import React, { Component } from 'react';
import ReactHighcharts from 'react-highcharts'
import { allViewConfig } from './graphConfigs/graphConfigs';

class Graph extends Component {
  afterRender = (chart) => {
    function draggablePlotLine(axis, plotLineId) {
        var clickX, clickY;

        var getPlotLine = function () {
            for (var i = 0; i < axis.plotLinesAndBands.length; i++) {
                if (axis.plotLinesAndBands[i].id === plotLineId) {
                    return axis.plotLinesAndBands[i];
                }
            }
        };

        var getValue = function() {
            var plotLine = getPlotLine();
            var translation = axis.horiz ? plotLine.svgElem.translateX : plotLine.svgElem.translateY;
            var new_value = axis.toValue(translation) - axis.toValue(0) + plotLine.options.value;
            new_value = Math.max(axis.min, Math.min(axis.max, new_value));
            return new_value;
        };

        var drag_start = function (e) {
            $(document).bind({
                'mousemove.line': drag_step,
                    'mouseup.line': drag_stop
            });

            var plotLine = getPlotLine();
            clickX = e.pageX - plotLine.svgElem.translateX;
            clickY = e.pageY - plotLine.svgElem.translateY;
            if (plotLine.options.onDragStart) {
                plotLine.options.onDragStart(getValue());
            }
        };

        var drag_step = function (e) {
            var plotLine = getPlotLine();
            var new_translation = axis.horiz ? e.pageX - clickX : e.pageY - clickY;
            var new_value = axis.toValue(new_translation) - axis.toValue(0) + plotLine.options.value;
            new_value = Math.max(axis.min, Math.min(axis.max, new_value));
            new_translation = axis.toPixels(new_value + axis.toValue(0) - plotLine.options.value);
            plotLine.svgElem.translate(
                axis.horiz ? new_translation : 0,
                axis.horiz ? 0 : new_translation);

            if (plotLine.options.onDragChange) {
                plotLine.options.onDragChange(new_value);
            }
        };

        var drag_stop = function () {
            $(document).unbind('.line');

            var plotLine = getPlotLine();
            var plotLineOptions = plotLine.options;
            //Remove + Re-insert plot line
            //Otherwise it gets messed up when chart is resized
            if (plotLine.svgElem.hasOwnProperty('translateX')) {
                plotLineOptions.value = getValue()
                axis.removePlotLine(plotLineOptions.id);
                axis.addPlotLine(plotLineOptions);

                if (plotLineOptions.onDragFinish) {
                    plotLineOptions.onDragFinish(plotLineOptions.value);
                }
            }

            getPlotLine().svgElem
                .css({'cursor': 'pointer'})
                .translate(0, 0)
                .on('mousedown', drag_start);
        };
        drag_stop();
    };
  }

  render(){
    return (
      <div>
        <ReactHighcharts
          config={allViewConfig(this.props.configArr, this.props.bandRow, this.props.configVars)}
          callback = {this.afterRender}
        />
      </div>
    );
  }
};

export default Graph;
BJax
  • 153
  • 9

1 Answers1

2

Got it working. There were several points that needed adjustment.

  1. Needed to follow the React-Highcharts optional after-render callback format.
  2. Convert any JQuery manipulation to vanilla so that it works will with React. Basically go through and replace all of the $
  3. For my puroses the onDragStart, onDragChange and onDragFinish in the yAxis config were not necessary. If you do need/want them just convert the JQuery and like in step 2 and you will be good to go.
  4. Bonus Tip: If you are saving the new position in Redux watch out for the chart re rendering when you update it. This was causing some odd bugs that where hard to figure out until i realized that setting information in Redux was causing my chart to re render.

Below is the code for the working ReactHighcharts component.

import React, { PureComponent } from 'react';
import ReactHighcharts from 'react-highcharts'
import { allViewConfig } from './graphConfigs/graphConfigs';

import moment from 'moment'

class Graph extends PureComponent {

// Step 1a code 

  afterRender = (chart) => {
        // this.draggablePlotLine(chart.xAxis[0], 'foo');
        this.draggablePlotLine(chart.yAxis[0], 'plotLineIdOpen');
        this.draggablePlotLine(chart.yAxis[0], 'plotLineIdClose');
        console.log('ready');
    }
// End Step 1a code 

  draggablePlotLine = (axis, plotLineId) => {
          var clickX, clickY;

          var getPlotLine = () => {
              for (var i = 0; i < axis.plotLinesAndBands.length; i++) {
                  if (axis.plotLinesAndBands[i].id === plotLineId) {
                      return axis.plotLinesAndBands[i];
                  }
              }
          };

          var getValue = () => {
              var plotLine = getPlotLine();
              var translation = axis.horiz ? plotLine.svgElem.translateX : plotLine.svgElem.translateY;
              var new_value = axis.toValue(translation) - axis.toValue(0) + plotLine.options.value;
              new_value = Math.max(axis.min, Math.min(axis.max, new_value));
              return new_value;
          };

          var drag_start = (e) => {
// Step 2a code 
              document.addEventListener('mousemove', drag_step);
              document.addEventListener('mouseup', drag_stop);
// Step 2a code 

              var plotLine = getPlotLine();
              clickX = e.pageX - plotLine.svgElem.translateX;
              clickY = e.pageY - plotLine.svgElem.translateY;
              if (plotLine.options.onDragStart) {
                  plotLine.options.onDragStart(getValue());
              }
          };

          var drag_step = (e) => {
              var plotLine = getPlotLine();
              var new_translation = axis.horiz ? e.pageX - clickX : e.pageY - clickY;
              var new_value = axis.toValue(new_translation) - axis.toValue(0) + plotLine.options.value;
              new_value = Math.max(axis.min, Math.min(axis.max, new_value));
              new_translation = axis.toPixels(new_value + axis.toValue(0) - plotLine.options.value);
              plotLine.svgElem.translate(
                  axis.horiz ? new_translation : 0,
                  axis.horiz ? 0 : new_translation);

              if (plotLine.options.onDragChange) {
                  plotLine.options.onDragChange(new_value);
              }
          };

          var test = (value) => {
            console.log(value);
            console.log(this);
            this.props.updateState({key:['plotClose'], value: 'test' });
            // this.props.updateState({key:['plotOpen'], value: value });

          }

          var drag_stop = () => {
// Step 2b code 
              document.removeEventListener('mousemove', drag_step);
              document.removeEventListener('mouseup', drag_stop);
// Step 2b code 

              var plotLine = getPlotLine();
              var plotLineOptions = plotLine.options;
              //Remove + Re-insert plot line
              //Otherwise it gets messed up when chart is resized
              if (plotLine.svgElem.hasOwnProperty('translateX')) {
                  plotLineOptions.value = getValue()
                  // console.log(moment.utc(plotLineOptions.value).format('MMMM Do YYYY, h:mm:ss a'));
                  // console.log(plotLineOptions);
                  axis.removePlotLine(plotLineOptions.id);
                  axis.addPlotLine(plotLineOptions);

                  if (plotLineOptions.onDragFinish) {
                      plotLineOptions.onDragFinish(plotLineOptions.value);
                  }
              }

              getPlotLine().svgElem
                  .css({'cursor': 'pointer'})
                  .translate(0, 0)
                  .on('mousedown', drag_start);

          };
          drag_stop();
      }

  render(){
    return (
      <div>
        <ReactHighcharts
          config={allViewConfig(this.props.configArr.toArray(), this.props.bandRow, this.props.configVars)}

// Step 1b code 
          callback = {this.afterRender}
// End Step 1b code 
        />
      </div>
    );
  }
};

export default Graph;
BJax
  • 153
  • 9