How can I create a horizontal scrolling Chart.js line chart with a locked y axis?

后端 未结 7 1807
生来不讨喜
生来不讨喜 2020-11-29 00:39

I\'d like to create a line chart with Chart.Js but have the Y-Axis not move when I scroll.

I\'m assuming I can use a fixed width, and put i

相关标签:
7条回答
  • 2020-11-29 00:50

    Chart.js 2.x:

    CSS:

        .graph {
            padding: 10px;
            position: relative;
            overflow-x: scroll;
            width: 100%;
            .graph-container {
                height: 500px;
                width: 100%;
                min-width: 100%
            }
        }
    

    HTML : Ignore the angular ngFor

      <div *ngFor="let graph of graphs; let i = index" class="graph">
            <div class="graph-container">
                <canvas #graphCanvas></canvas>
            </div>
      </div>
    

    JS

    Set these options:

            options: {
                responsive: true,
                maintainAspectRatio: false
            }
    

    Set the width of the "graph-container"

    I'm setting the width based on the number of elements I have X a zoom that the user chooses

    graphCanvasElement.nativeElement.parentElement
        .setAttribute('style', `width: ${chartData.data.labels.length*graph.zoom}px;min-width: 100%`);
    
    graph.chartObj = new Chart(graphCanvasElement.nativeElement.getContext('2d'), chartData);
    
    0 讨论(0)
  • 2020-11-29 00:51

    To add to Emma Louise's solution above (I don't have the reputation to comment), I found that if I filled the rectangle with a color before drawing the image, the overlay canvas is opaque. Then you don't need to worry about clearing the rectangle, either onProgress or onComplete.

        targetCtx.fillStyle = 'white'
        targetCtx.fillRect(0, 0, copyWidth * scale, copyHeight * scale);
    

    Also, maybe it's because my devicePixelRatio is one, but these two lines caused the text in my chart to be all fuzzy. It looks fine when I remove them.

        targetCtx.canvas.style.width = `${copyWidth}px`;
        targetCtx.canvas.style.height = `${copyHeight}px`;
    
    0 讨论(0)
  • 2020-11-29 01:02

    Scrollable Chart

    You're pretty much on the right track. If you add another wrapper and the y axis you are done.


    Preview


    CSS

    .chartWrapper {
        position: relative;
    }
    
    .chartWrapper > canvas {
        position: absolute;
        left: 0;
        top: 0;
        pointer-events:none;
    }
    
    .chartAreaWrapper {
        width: 600px;
        overflow-x: scroll;
    }
    

    HTML

    <div class="chartWrapper">
        <div class="chartAreaWrapper">
            <canvas id="myChart" height="300" width="1200"></canvas>
        </div>
        <canvas id="myChartAxis" height="300" width="0"></canvas>
    </div>
    

    Script

    ...
    
    new Chart(ctx).Line(data, {
        onAnimationComplete: function () {
            var sourceCanvas = this.chart.ctx.canvas;
            // the -5 is so that we don't copy the edges of the line
            var copyWidth = this.scale.xScalePaddingLeft - 5;
            // the +5 is so that the bottommost y axis label is not clipped off
            // we could factor this in using measureText if we wanted to be generic
            var copyHeight = this.scale.endPoint + 5;
            var targetCtx = document.getElementById("myChartAxis").getContext("2d");
            targetCtx.canvas.width = copyWidth;
            targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
        }
    });
    

    Fiddle - http://jsfiddle.net/mbhavfwm/

    0 讨论(0)
  • 2020-11-29 01:02

    with the latest version (2.4.0) this worked for me:

    HTML

    <div style="width: 100%; overflow-x: auto; overflow-y: hidden">
      <div style="width: 3000px; height: 300px">
        <canvas id="chart1" height="300" width="0"></canvas>
      </div>
    </div>
    

    You can also calculate the width dynamically based on the length of data. For example in VueJS you can do it as follow (considering 30px for each entry):

    VueJS

    <div style="width: 100%; overflow-x: auto;">
      <div :style="{width: (data.length * 30) + 'px', height: '300px'}">
        <canvas id="chart1" height="300" width="0"></canvas>
      </div>
    </div>
    
    0 讨论(0)
  • 2020-11-29 01:02

    All these answers are rather muddy and complex.. Heres what I went with for my project. I just call fitChart() whenever the dataset changes or the container size changes.

    HTML:

    <div class="chartWrapper">
        <div class="chartContainer">
            <canvas id="chart"></canvas>
        </div>
    </div>
    

    CSS: (Set the width and height to whatever you want)

    div.chartWrapper {
        position: relative;
        overflow: auto;
        width: 100%;
    }
    
    div.chartContainer {
        position: relative;
        height: 300px;
    }
    

    JS:

    var xAxisLabelMinWidth = 15; // Replace this with whatever value you like
    var myChart = new Chart(document.getElementById('chart').getContext('2d'), {
        type: 'line',
        data: {},
        options: {
            responsive: true,
            maintainAspectRatio: false
        }
    });
    
    function fitChart(){
        var chartCanvas = document.getElementById('chart');
        var maxWidth = chartCanvas.parentElement.parentElement.clientWidth;
        var width = Math.max(mayChart.data.labels.length * xAxisLabelMinWidth, maxWidth);
    
        chartCanvas.parentElement.style.width = width +'px';
    }
    
    0 讨论(0)
  • 2020-11-29 01:04

    <ion-content > <div scrollX="true" scrollY="true" style="overflow:scroll; position:fixed; display:inline; top:0; right:0; bottom:0; left:0; white-space: nowrap;"> <canvas baseChart [data]="barChartData" [labels]="barChartLabels" [options]="barChartOptions" [colors]="lineChartColors" [legend]="barChartLegend" [chartType]="barChartType" (chartHover)="chartHovered($event)" (chartClick)="chartClicked($event)"> </canvas> </div> <button (click)="randomize()">Update</button> </ion-content>

    It works for me as I set canvas width 700 px and scroll works smoothly.

    0 讨论(0)
提交回复
热议问题