Search code examples
javascriptreact-chartjsreact-chartjs-2

Chartjs using react - create viewport that slides along x axis, where x axis has a hard minimum and maximum


I'm trying to create and control a viewport where you can scroll left or right on a chart in chartjs, but havent been having any luck. I need the min and max X values to be a hard stop on the panning functionality.

screenshot

So, in the screenshot the red box would be what the user sees, which maintains a fixed width on the X-Axis (say 8 hours), and the left "1500" would be the farthest left the viewport goes, and the 0400 outside the box is the furthest right.

This is what i have right now:

import moment from "moment";
import Chart from "chart.js/auto";
import { Bar } from "react-chartjs-2";
import zoomPlugin from 'chartjs-plugin-zoom';
import annotationPlugin from 'chartjs-plugin-annotation';
import 'chartjs-adapter-moment';

Chart.register(annotationPlugin,zoomPlugin);

const r = document.querySelector(':root');
const rs = getComputedStyle(r);

const data = {
    datasets: [
      {
        type: 'bar',
        data: [], //value - set through programming
        order: 1
      },
      {
        type: 'bar',
        data: [],
        order: 1
      },
      {
        type: 'bar',
        data: [],
        order: 1
      },
      {
        type: 'bar',
        data: [],
        order: 1
      },
      {
        data: [],
        type: 'line',
        order: 0,
        steppedLine: true,
        stepped: 'before'
       },
       {
        label: "Current Time", //needed for legend
        type: 'line'
       }
    ]
  };

const options = {
    plugins: {
        legend: {
          position: 'bottom',
        },
        annotation:{
            annotations: [{
                type: 'line',
                borderColor: rs.getPropertyValue('--CURRENT_TIMELINE'),
                borderWidth: 2,
                mode: 'vertical',
                xMin: moment().subtract(30, "m").valueOf(),
                xMax: moment().subtract(30, "m").valueOf()
            }]
        }
    },
    zoom: {
        pan: {
            enabled: true
        }
    },
    elements: {
        point:{
            radius: 0
        }
    },
    scales: {
        x: {
            stacked: true,
            display: true,
            offset: false,
            title: {
                display: false,
                text: 'Time'
            },
            type: 'time',
            time: {
                unit: 'hour',
                displayFormats: {
                  'minute': 'HHmm',
                  'hour': 'HHmm',
                }
            },
            ticks: {
                // forces step size to be 50 units
                stepSize: 1
              }
        },
        y: {
            stacked: true,
            min: 0,
            title: {
                display: true,
                text: 'My title'
            }
        }
    }
};

class myChart extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            data: data,
            options: options
        }
    }

    render() { 
        return (
            <div className="chart" id="chart">
                <Bar data={this.state.data} options={this.state.options}/>
            </div>
        );
    }
    }

export default myChart;

Currently, the chart wont pan because it always shows the data for the entire range, and i dont know how to fix that or what setting that is in the documentation.

Any help is always appreciated.


Solution

  • so i figured it out. the issue is with the options tag:

    const options = {
        plugins: {
            legend: {
              position: 'bottom',
            },
            annotation:{
                annotations: [{
                    type: 'line',
                    borderColor: rs.getPropertyValue('--CURRENT_TIMELINE'),
                    borderWidth: 2,
                    mode: 'vertical',
                    xMin: moment().subtract(30, "m").valueOf(),
                    xMax: moment().subtract(30, "m").valueOf()
                }]
            },
            zoom: {
                pan: {
                   enabled: true
                }
               limits: {
                  x: 
                 {
                     min: moment().subtract(30, "m").valueOf(),
                     max: moment().add(30, "m").valueOf()
                  }
               },
           }
        },
        ...
    

    The zoom option needed to be in the plugin section, and the limit value needed to be added to establish the x min and max values that the viewport would pan to, and the options.scales.x.min / max sets the viewport.

    Thank you for the help, but the answer i used is now deleted, so this will be marked as the answer.