Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Can't get chart instance with composition api #1012

Open
1 task
tonylee00111 opened this issue Mar 20, 2023 · 12 comments
Open
1 task

[Bug]: Can't get chart instance with composition api #1012

tonylee00111 opened this issue Mar 20, 2023 · 12 comments

Comments

@tonylee00111
Copy link

Would you like to work on a fix?

  • Check this if you would like to implement a PR, we are more than happy to help you go through the process.

Current and expected behavior

Can't get chart instance by ref. Chart ref value always return null

This is my code

<template>
  <Bar ref="myChart" :data="chartData" :options="chartOptions" />
</template>

<script>
import {
  Chart as ChartJS,
  Title,
  Tooltip,
  Legend,
  BarElement,
  CategoryScale,
  LinearScale,
} from 'chart.js';
import { defineComponent, computed, onMounted, ref } from 'vue';
import { Bar } from 'vue-chartjs';
import * as chartConfig from './chartConfig.js';

ChartJS.register(
  CategoryScale,
  LinearScale,
  BarElement,
  Title,
  Tooltip,
  Legend
);

export default defineComponent({
  setup(props) {
    const myChart = ref(null);
    const chartData = ref(chartConfig.data);
    const chartOptions = ref(chartConfig.options);

    onMounted(() => {
      console.log(myChart.value.chart);  <-- chart will be null 
    });

    return {
      myChart,
      chartData,
      chartOptions,
    };
  },
  components: {
    Bar,
  },
});
</script>

Reproduction

https://stackblitz.com/edit/github-62t8lr?file=src/App.vue

chart.js version

^4.0.0

vue-chartjs version

^5.0.0

Possible solution

No response

@DRoet
Copy link

DRoet commented Apr 5, 2023

I'm seeing the same thing when using Vue 2.7 and this.$refs.refname.chart. the object key exists but is always null

@apertureless
Copy link
Owner

Hm thats weird. Because if you console.log myChart.value it shows the chart attribute. I will look into it.

image

@palsingh
Copy link

It seems that chart is not available when onMounted is called.
If you use nextTick, then you can access the chart object.

onMounted(async () => {
    await nextTick()
    console.log('test: ', mychart.value.chart);
})

@dnkmdg
Copy link

dnkmdg commented Jun 21, 2023

I'm seeing the same behavior when running in <script setup>. When logging the chart ref in onExportImageClick it's always undefined.

EDIT: I found a way seconds after posting. So the ref isn't bound the same way in Composition as it would be in Options API, but accessing the ref and instead looking at chartInstance solved my problem. Code updated with working example:

<template>
    <div class="relative ">
        <PieChart
            ref="chart"
            :chart-data="chartData"
            :options="chartOptions"
            :height="height"
            :css-classes="cssClasses"
        />

        <div class="absolute top-0 right-0 px-2 py-1 space-x-2">
            <OutlineButton size="xs" class="py-1.5 !px-1.5 !text-base">
                <Fa :icon="['far','file-csv']" fixed-width />
            </OutlineButton>
            <OutlineButton
                size="xs"
                class="py-1.5 !px-1.5 !text-base"
                @click="onExportImageClick"
            >
                <Fa :icon="['far','file-image']" fixed-width />
            </OutlineButton>
        </div>
    </div>
</template>

<script setup>
import { Chart, registerables } from 'chart.js'
import { computed, nextTick, ref } from 'vue'
import { PieChart } from 'vue-chart-3'
import { emptyChartPlugin } from '@/Modules/Charts/ChartHelpers'
import OutlineButton from '../OutlineButton.vue'

Chart.defaults.font.family = 'Inter'
Chart.register(...registerables, emptyChartPlugin)

const props = defineProps({
    options: {
        type: Object,
        default: null,
    },
    data: {
        type: Object, 
        default: null,
    },
    height: {
        type: Number,
        default: 400,
    },
    cssClasses: {
        type: String, 
        default: '',
    },
})

const chart = ref(null)

const chartData = computed(() => {
    return props.data
})
const chartOptions = computed(() => {
    return props.options
})

const onExportImageClick = () => {
        //Correctly logs Chart instance for interaction
        console.log(chart.value.chartInstance)
}

</script>

@palsingh
Copy link

Isn't the property name chart instead of chartInstance?
Ex: chart.value.chart

@dnkmdg
Copy link

dnkmdg commented Jun 21, 2023

Isn't the property name chart instead of chartInstance? Ex: chart.value.chart

No, for some reason it isn't reflected like that when using Composition API.

@Rednas83
Copy link

@dnkmdg You are using vue-chart3 which is no longer maintained! Recommended is to use vue-chartjs.

I just started with migrating. from vue-chart3 Is there also a composition example preferably in typescript?

Something like:

<script setup lang="ts">
import { Line, Pie,  } from "vue-chartjs"
</script>

@tpfau
Copy link

tpfau commented Jun 29, 2023

I'm seeing the same situation in the options api.
I wanted to listen to clicks on the points of a scatter plot, and thus wanted to access the chart. But during mounted() the chart property of the ref returns as null. More precisely, it returns as a proxy with this structure in the dev-tools:

Proxy { <target>: Proxy, <handler>: {…} }
  <target>: Proxy { <target>: {…}, <handler>: {…} }
    <target>: Object { chart: {…}, … }
      __v_skip: true
      chart: Object { __v_isShallow: true, dep: undefined, __v_isRef: true, … }
      ​​​<prototype>: Object { … }
    ​​<handler>: Object { get: get(target, key, receiver), set: set(target, key, value, receiver)
    }
  ​<handler>: Object { get: get(target, key), has: has(target, key) }

And when trying to access the chart property, that property (at least during mounted the chart is null.

I'm actually happy for any hints as to how to listen to clicks on the chart by other means.

@quilkin
Copy link

quilkin commented Sep 30, 2023

This is working for 'onHover' event, using vue-chartjs / vue3 / compostion API:

const chart = ref(null) ;
....
....
onHover: (e) => {
            if (chart.value === null)
                return;
            const thisChart = chart.value.chart;
            const canvasPosition = getRelativePosition(e, thisChart);
            const dataX = thisChart.scales.x.getValueForPixel(canvasPosition.x);
            const dataY = thisChart.scales.y.getValueForPixel(canvasPosition.y);
            console.log('x: ' + dataX + ' y: ' + dataY)
        }
<template>
    <Line
        ref="chart"
        :data = "chartData"
        :options = "chartOptions"
    />
</template>

It's giving a typescript error for `chart.value.chart' because I cannot find the correct type definition for the chart isntance, but the code runs OK.

@jeroenpelgrims
Copy link

jeroenpelgrims commented Oct 25, 2023

@quilkin

It's giving a typescript error for `chart.value.chart' because I cannot find the correct type definition for the chart isntance, but the code runs OK.

import { ChartComponentRef } from "vue-chartjs";
...
const chart = ref<ChartComponentRef | null>(null)

or if you need more strict typing based on the chart type:

const chart = ref<ChartComponentRef<"line"> | null>(null)

@Rednas83

I just started with migrating. from vue-chart3 Is there also a composition example preferably in typescript?

For me the following works using @palsingh's workaround:

<script setup lang="ts">
import { nextTick, onMounted, ref } from "vue";
import { Line } from 'vue-chartjs'
import { ChartComponentRef } from "vue-chartjs";

const chart = ref<ChartComponentRef | null>(null)

onMounted(async () => {
	await nextTick()
	console.log(chart.value?.chart)
})
</script>

<template>
	<Line ref="chart" :data="<data>" :options="<options>" />
</template>

@quilkin
Copy link

quilkin commented Oct 25, 2023

@jeroenpelgrims
Thanks for suggestion - ChartComponentRef solved that error but now getRelativePosition is complaining:

Argument of type '{ readonly platform: { acquireContext: (canvas: HTMLCanvasElement, options?: CanvasRenderingContext2DSettings | undefined) => CanvasRenderingContext2D | null; ... 6 more ...; updateConfig: (config: ChartConfiguration<...> | ChartConfigurationCustomTypesPerDataset<...>) => void; }; ... 46 more ...; getContext: () => ...' is not assignable to parameter of type 'Chart'. Type 'null' is not assignable to type 'Chart'.ts(2345)

@Rednas83
Copy link

Rednas83 commented Feb 6, 2024

@jeroenpelgrims Just tried the solution but it doesn't seem to work anymore😢

Because I am getting the folowing runtime error
image

Only modified it a little by adding some data and options.

<script setup lang="ts">
import { nextTick, onMounted, ref } from "vue"
import { Line } from "vue-chartjs"
import type { ChartComponentRef } from "vue-chartjs"

const chart = ref<ChartComponentRef | null>(null)
const chartData = ref({
  labels: ["January", "February", "March"],
  datasets: [{ data: [40, 20, 12] }],
})
const chartOptions = ref({
  responsive: true,
})

onMounted(async () => {
  await nextTick()
  console.log(chart.value?.chart)
})
</script>

<template>
  <Line ref="chart" :data="chartData" :options="chartOptions" />
</template>

I am using the latest packages

------------------------------
- Operating System: Windows_NT
- Node Version:     v20.10.0
- Nuxt Version:     3.10.1
- CLI Version:      3.10.0
- Nitro Version:    2.8.1
- Package Manager:  pnpm@8.15.1
- Builder:          -
- User Config:      telemetry, vite, modules, build, routeRules, components, content, formkit, imports, css, devtools
- Runtime Modules:  @vueuse/nuxt@10.7.2, normalizedModule(), @nuxt/content@2.12.0, @pinia/nuxt@0.5.1, @nuxtjs/tailwindcss@6.11.3, nuxt-icon@0.6.8, @formkit/nuxt@1.5.5
- Build Modules:    -
------------------------------

Does anyone has a working solution for nuxt with the composition api?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants