econnomnomnom
Posts: 9
Joined: Fri Oct 08, 2021 7:17 am

Including multiple click-and-drag events in the same chart

I have a chart that displays a time series called pi. I want people to look at this time series and guess what they think will be true of the time series at the end of today (i.e. a nowcast) and tomorrow (i.e. a forecast). I want people to be able to click on the chart to input these guesses. When they click on the chart, I want a marker to appear wherever they click. I then want them to be able to drag this market up and down (but not horizontally) until they are happy with their guess values.

I am able to make this work if only collecting one guess but not both simultaneously. If I try to do this with two inputs, the code behaves exactly the same way as it did when I first added the click and drag events for only one of the inputs. Is there a way to localize click events to certain ranges of the x-axis or some other obvious solution?
jedrzej.r
Posts: 725
Joined: Tue Jan 24, 2023 11:21 am

Re: Including multiple click-and-drag events in the same chart

Hi!

Thanks for contacting us with your question!

To achieve described effect, you can include draggable-points module to your solution, which adds a user friendly points dragging feature.

Demo: https://jsfiddle.net/BlackLabel/ytxv6a08/

As for restricting clicks on certain area, you could check if click occured between chosen xAxis positions (e.g. 4 - 5.5), and then add point.

References:
https://api.highcharts.com/highstock/se ... e.dragDrop
https://api.highcharts.com/class-refere ... #addSeries
https://api.highcharts.com/class-refere ... s#addPoint

Let me know if this was what you were looking for!
Best regards!
Jędrzej Ruta
Highcharts Developer
econnomnomnom
Posts: 9
Joined: Fri Oct 08, 2021 7:17 am

Re: Including multiple click-and-drag events in the same chart

Not exactly.

I will include my current code below to give you a better idea of what I am doing.

Essentially, I have two series: nowcast and forecast. I want a person interacting with my chart, in each period p, to be able to provide a nowcast of a series called S. To do this, I would like them to be able to click on the chart within a shaded region around period p to add an to the series called nowcast and then drag that point up and down until they are happy with that value. Then, I would like them to be able to do the same with a shaded area around p+1 to add an entry to the forecast series.

I am able to do exactly what I want for the nowcast series. However, I haven't been able to figure out how to do it for both nowcast and forecast.


Here is my current code:

Code: Select all


  Highcharts.setOptions({
        plotOptions: {
            series: {
                animation: false,
                pointStart: 1,
              label: {
                enabled: false,
            }}}
                
     
        });
    let current_round = {{current_round}}
    let next_round = current_round+1
    let low = {{current_round}} - .25
    let high = {{current_round}} + .25
    let low2 = low + 1 
    let high2 = high + 1 
    let axis_high = {{current_round}} + 3
    let axis_low = {{current_round}} - 3
    
//draw chart 
myChart = Highcharts.chart('container', {
   
    chart: {
          type: "line",
          events: {
            click: function (e) {
              // find the clicked values and the series
              var y = e.yAxis[0].value,
              x=current_round
              series = this.series[0].data[current_round-1];
              series.update({x, y, color: 'red'});
            },
            drag: function (e) {
              var y = e.yAxis[0].value,
              x=current_round
              series = this.series[0].data[current_round-1];
              series.update({x, y, color: 'red'});
            }
          }
        },

        title: {
          text: "" //no title for now 
        },

     xAxis: {
       type: 'category',
          allowDecimals: true,
          min: axis_low,
          max: axis_high,
          scrollbar: {
            enabled: true,
            liveRedraw: false
        },
         title: {
            text: "Period"
          },
          plotBands: [{
            color: 'rgba(255,0,0,0.25)', // Color value
            from: low, // Start of the plot band
            to: high, // End of the plot band
           label: {
                text: '<b>Nowcast</b> <br> <b>Today</b>',
                align: 'center',
                y: 300
            }},{
            color: 'rgba(0,0,255,0.25)', // Color value
            from: low2, // Start of the plot band
            to: high2, // End of the plot band
           label: {
                text: '<b>Forecast</b> <br> <b>Today</b>',
                align: 'center',
                y: 300
            }
          }]               
    },
    yAxis: {
          title: {
            text: "Inflation (%)"
          },
          minRange: 10,
          plotLines: [{
            value: 0,
            width: 2,
            color: '#aaa',
            zIndex: 10
          }]
        },
        tooltip: {
          style: {
            color: 'black',
            fontWeight: 'bold',
            fontSize: 12
          },
          positioner: function () {
            return { x: 80, y:0 };
          },
          shared: true,
          headerFormat: '',
          valueDecimals: 2,
          shadow: false,
          borderWidth: 2,
          borderColor: '#000000',
          shape: 'rect',
          backgroundColor: 'rgba(255,255,255,0.8)'
        },
    

    legend: {
        layout: 'vertical',
        align: 'right',
        verticalAlign: 'middle'
    },

    plotOptions: {
        series: {
            label: {
                connectorAllowed: false,
            },
            pointStart: 1
        }
    },

    series: [
        {
              dragDrop: {
                draggableY: true,
                dragMinY: -100,
                dragMaxY: 100,
                dragPrecisionY: .01, 
                liveRedraw: false,
              },
              point: {
                events: {
                  update: (event) => {
                    const clickedYValue = event?.options?.y;
                    //if clickedYValue is of type number,
                    if (typeof clickedYValue === 'number') {
                      const roundedPointForecast = Math.round(clickedYValue * 100) / 100;
                      const expectedInflationInput = document.getElementById('id_e_pi_today');
                      expectedInflationInput.value = roundedPointForecast;
                      const graphInput = document.getElementById('input_id');
                      graphInput.value = roundedPointForecast;
                    }
                    //else do not update.
                  },
                  drag: function() {
                    if (this.color !== 'red') {
                       return false;
                    }
                  },
                  drop: function() {
                    if (this.color !== 'red') {
                       return false;
                    }
                  }, 
                }
              },
        name: 'Nowcast',
        data: {{today_pi}},
        color: 'red',
        tooltip: {
              pointFormat: '<span style="color:red">\u25CF</span> {series.name}: <b>{point.y}</b><br/>',
            },
            marker: {
              radius: 2.5,
              fillColor: 'red',
              symbol:'circle'
            }
    }, {

        name: 'Forecast',
        data: {{tomorrow_pi}},
        color: 'blue', 
         tooltip: {
              pointFormat: '<span style="color:blue">\u25CF</span> {series.name}: <b>{point.y}</b><br/>',
            },
            marker: {
              radius: 2.5,
              fillColor: 'blue',
              symbol:'diamond'
            }
        
    }, {
        name: 'Realized Inflation',
        data: {{realized_inflation}},
        color: 'purple',
              
        marker: {
              radius: 2.5,
              symbol: 'square'
            }
    }, {
        name: 'Inflation Target',
        data: {{inflation_target}},
        color: 'black',
         dashStyle: 'dash',
        marker: {
              radius: 2.5,
              symbol:'triangle'
            }
    }],

    responsive: {
        rules: [{
            condition: {
                maxWidth: 500
            },
            chartOptions: {
                legend: {
                    layout: 'horizontal',
                    align: 'center',
                    verticalAlign: 'bottom'
                }
            }
        }]
    }

});

econnomnomnom
Posts: 9
Joined: Fri Oct 08, 2021 7:17 am

Re: Including multiple click-and-drag events in the same chart

Fixed it! I just retrieved the x-axis value of the click using var = e.xAxis[0].value and then used conditional statements so that the click event would update the two different series depending on whether or not var was within one of two sets of x-axis bounds.



Thanks for the help!
jedrzej.r
Posts: 725
Joined: Tue Jan 24, 2023 11:21 am

Re: Including multiple click-and-drag events in the same chart

Glad I could help you with your problem!

​If you have further inquiries, you may reach out to me at any time.
Best regards!
Jędrzej Ruta
Highcharts Developer

Return to “Highcharts Usage”