dreanor
dreanor

Reputation: 75

Resizing all charts dynamically in fixed size container in chart.js

I'm using chart.js (or more specifically vue-chartjs) for a component I want to use on a dashboard page. The user is supposed to be able to add new charts to the component using the dashboard. Since the component itself is of fixed size, I need the charts to properly align themselves and more importantly, resize in order to fit their parent container. I tried out a bunch of things but most ended with either the charts not filling out the container properly or overflowing the container vertically. Here is my code:

<script setup>
import { ref, onMounted } from 'vue';
import VueSlider from 'vue-slider-component';
import 'vue-slider-component/theme/default.css';
import { Doughnut } from 'vue-chartjs';
import { Chart as ChartJS, registerables } from 'chart.js';

ChartJS.register(...registerables);

const data1 = {
  // not relevant
};

const minYear = 2010;
const maxYear = 2024;
const charts = ref([]);
const isPlaying = ref(false);
const currentYear = ref(minYear);
let animationFrame = null;

function updateCharts() {
  charts.value.forEach(chartData => {
    chartData.data = data1[currentYear.value];
  });
}

function addChart(data, colors) {
  const chartData = ref(data[currentYear.value]);

  const chart = {
    chart: null,
    data: chartData,
    colors: colors
  };

  charts.value.push(chart);
}

function playSlider() {
  // not relevant
}

function handleSliderChange(value) {
  if (value >= minYear && value <= maxYear && value != currentYear.value) {
    currentYear.value = value;
    updateCharts();
  }
}

onMounted(() => {
  const colors1 = ['#36A2EB', '#FF6384', '#FFCE56'];

  addChart(data1, colors1);
});
</script>

<template>
  <div id="main">
    <div id="chartContainers" class="chart-container">
      <div v-for="(chartData, index) in charts" :key="index" class="chart-wrapper">
        <div class="canvas-container">
          <Doughnut
              :data="{ labels: ['Male', 'Female', 'NB'], datasets: [{ data: chartData.data, backgroundColor: chartData.colors }] }"
              :options="{ responsive: true, maintainAspectRatio: false, animation: { animateRotate: true, animateScale: true }, plugins: { tooltip: { enabled: true } } }"
          />
        </div>
      </div>
    </div>
    <vue-slider id="yearSlider" v-model="currentYear" :min="minYear" :max="maxYear" :interval="1" @change="handleSliderChange" :disabled="isPlaying"/>
    <p id="currentYear">Year: {{ currentYear }}</p>
    <button id="playButton" @click="playSlider">{{ isPlaying ? 'Pause' : 'Play' }}</button>
  </div>
</template>

<style>
#main {
  width: 1000px;
  height: 1000px;
  position: absolute;
  top: 0;
  bottom: 100;
  left: 0;
  right: 0;
  margin: auto;
}
.chart-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-height: 40%;
  gap: 20px;
  margin: auto;
  padding-top: 20px;
}
.chart-container .chart-wrapper {
  flex: 1 1 45%;
  max-width: 45%;
  min-width: 300px;
  position: relative;
}
.canvas-container {
  width: 100%;
  height: 40vh;
  position: relative;
}
canvas {
  width: 100%;
  height: 100%;
}
#yearSlider {
  width: 100%;
  margin-top: 20px;
}
#currentYear {
  text-align: center;
  margin-top: 10px;
}
#playButton {
  display: block;
  margin: 20px auto;
  padding: 10px 20px;
  text-align: center;
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 5px;
}
</style>

Can someone help?

Upvotes: 0

Views: 135

Answers (0)

Related Questions