[Chartjs]-How to implement linked charts using Chart.JS

2👍

There are probably some other ways (maybe even some nicer ways), but this is how I would do this quick and dirty.

In the onClick event I would set the data for the other Chart and than just call updateon the second chart. (link to the documentation)

Here a demo, how I would do this:
(Click on the pieChart to see the LineChart)

// Original Data
let dataSet = [
    {"date": "06/01/2023 16:45", "item": "Apple", "cat": "Fruit", "price": "9.00"},
    {"date": "06/01/2023 16:45", "item": "Orange", "cat": "Fruit", "price": "8.00"},
    {"date": "06/01/2023 16:45", "item": "Pear", "cat": "Fruit", "price": "7.00"},
    {"date": "06/01/2023 16:45", "item": "Water", "cat": "Drink", "price": "2.00"},
    {"date": "06/01/2023 16:45", "item": "Soda", "cat": "Drink", "price": "3.00"},
    {"date": "07/01/2023 16:45", "item": "Apple", "cat": "Fruit", "price": "9.50"},
    {"date": "07/01/2023 16:45", "item": "Orange", "cat": "Fruit", "price": "8.50"},
    {"date": "06/01/2023 16:45", "item": "Pear", "cat": "Fruit", "price": "7.50"},
    {"date": "07/01/2023 16:45", "item": "Water", "cat": "Drink", "price": "2.50"},
    {"date": "07/01/2023 16:45", "item": "Soda", "cat": "Drink", "price": "3.50"}
]

// pre split data
let drinkData = dataSet.filter(n => n.cat =='Drink')
let fruitData = dataSet.filter(n => n.cat =='Fruit')

let fruitDataSets = []
let drinkDataSets = []

let lineChartColors = ['#4BC0C0', '#FF9F40', '#9966FF']

// prepare Data for LineChart -- START
let formatedData = fruitData.reduce((p,c) => {
        if(!p[c.item]){
            p[c.item] = []
        }
        p[c.item].push({x: new Date(c.date), y: parseFloat(c.price), label: c.item})
        return p
    }, {});

Object.values(formatedData).forEach((n, i) => fruitDataSets.push({
  data: n, 
  label: n[0].label, 
  backgroundColor: lineChartColors[i],
  borderColor: lineChartColors[i]
}));
                
formatedData = drinkData.reduce((p,c) => {
        if(!p[c.item]){
            p[c.item] = []
        }
        p[c.item].push({x: new Date(c.date), y: parseFloat(c.price), label: c.item})
        return p
    }, {});

Object.values(formatedData).forEach((n, i) => drinkDataSets.push({
  data: n, 
  label: n[0].label, 
  backgroundColor: lineChartColors[i],
  borderColor: lineChartColors[i]
}));

// prepare Data for LineChart -- END

// create data for the pieChart
let preparedPieData = dataSet.reduce((p,c) => {         
      p[c.cat]++
      return p
  }, { Drink:0, Fruit: 0});


const pieData = {
    //  create labels for the pieChart
    labels: Object.keys(preparedPieData),
    datasets: [{
        data: Object.values(preparedPieData), 
        backgroundColor: ['#35A2EB', '#FF6283'], 
        borderWidth: 1,
     }],
};

let lineData = {
    datasets: [],
};

// PieChart Configuration
const config = {
    type: 'pie',
    data: pieData,
    options: {
        maintainAspectRatio: false,
        onClick: function(e, item){
          lineData.datasets = item[0].index == 0 ? drinkDataSets : fruitDataSets
          lineChart.update();
       }
    }
};

// LineChart Configuration
const config2 = {
    type: 'line',
    data: lineData,
    options: {
        maintainAspectRatio: false,
        scales: {
            x: {
                type: 'time',
                time: {
                    unit: 'week'
                }
            }
        }
    }
};

new Chart(
    document.getElementById('chart1'),
    config
);

let lineChart = new Chart(
    document.getElementById('chart2'),
    config2
);
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.js"></script>     
<script src="//cdn.jsdelivr.net/npm/moment@^2"></script>
<script src="//cdn.jsdelivr.net/npm/chartjs-adapter-moment@^1"></script>
  

<div class="chart" style="float:left;height:184px; width:250px;">
    <canvas  id="chart1" ></canvas>
</div>

<div class="chart" style="float:left;height:184px; width:250px;">
    <canvas  id="chart2" ></canvas>
</div>

Leave a comment