victorgarciaesgi / vue-chart-3

📊 A simple wrapper around Chart.js 3 for Vue 2 & 3

Home Page:https://vue-chart-3.netlify.app/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Accessing the chartInstance for any processing purposes

TheCelebrimbor opened this issue · comments

How can I access the canvas or the chartInstance for any external purposes like saving it as png etc ? If I have the instance, I can call .toBase64Image() to get an image out of it.

Great work btw!.

Hi @TheCelebrimbor and thanks !
It should be already possible using template refs.

<template>
  <Bar ref='barChartRef'/>
</template>

<script>
   export default {
       mounted() {
             this.$refs.barChartRef.chartInstance.toBase64Image()
       }
   }
</script>

Keep me updated :)

I will add a section in the README for it!

@victorgarciaesgi Thanks for the quick reply.! I was able to access the canvasRef but not the chartInstance. It is null.
I am accessing the ref after all rendering is done with a custom save button.

image

Hum maybe it's because the chartInstance is not reactive. I will try something and keep you updated!

@TheCelebrimbor Can you try v0.2.3?
Are you on vue 2, because somewhat making chartInstance reactive doesn't seem to work on Vue 3 :(

@victorgarciaesgi I just updated to 0.2.3. It seems to break the whole thing. Now I get a new error whenever I interact with anything in the view containing the charts.

This even causes a stack overflow
image

Full Error:

runtime-core.esm-bundler.js:38 [Vue warn]: Unhandled error during execution of watcher callback 
  at <Bar ref="chartRef" data= {datasets: Array(1), labels: Array(4)}datasets: [{…}]labels: (4) ["Windows", "Linux", "Mac", "Unix"]__proto__: Object > 
  at <VsCard content="" fitContent="" > 
  at <Chart class="block-content" data= {componentName: "Chart.vue", h: "440px", w: "400px", title: "Computers by Platform", id: "chart-computers-by-platform", …} > 
  at <AsyncComponentWrapper class="block-content" data= {componentName: "Chart.vue", h: "440px", w: "400px", title: "Computers by Platform", id: "chart-computers-by-platform", …} > 
  at <Dashboard elements= (2) [{…}, {…}] id="computer-summary-dashboard" rows=1  ... > 
  at <Summary onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy {$vs: Proxy, …} > > 
  at <BaseTransition mode="out-in" appear=false persisted=false  ... > 
  at <Transition name="fade" mode="out-in" > 
  at <RouterView> 
  at <Admin onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy {$vs: Proxy, …} > > 
  at <RouterView> 
  at <App>
warn @ runtime-core.esm-bundler.js:38
logError @ runtime-core.esm-bundler.js:211
handleError @ runtime-core.esm-bundler.js:203
callWithErrorHandling @ runtime-core.esm-bundler.js:157
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:163
job @ runtime-core.esm-bundler.js:2077
flushPreFlushCbs @ runtime-core.esm-bundler.js:328
flushJobs @ runtime-core.esm-bundler.js:368
Promise.then (async)
queueFlush @ runtime-core.esm-bundler.js:286
queueCb @ runtime-core.esm-bundler.js:308
queuePreFlushCb @ runtime-core.esm-bundler.js:311
scheduler @ runtime-core.esm-bundler.js:2105
run @ reactivity.esm-bundler.js:183
trigger @ reactivity.esm-bundler.js:189
set value @ reactivity.esm-bundler.js:730
show @ vuesax3.common.js:57048
toggle @ vuesax3.common.js:57052
callWithErrorHandling @ runtime-core.esm-bundler.js:154
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:163
invoker @ runtime-dom.esm-bundler.js:308
helpers.segment.js:1795 Uncaught (in promise) RangeError: Maximum call stack size exceeded
    at _resolveWithPrefixes (helpers.segment.js:1795)
    at helpers.segment.js:1603
    at _cached (helpers.segment.js:1685)
    at Object.get (helpers.segment.js:1602)
    at _resolveWithContext (helpers.segment.js:1693)
    at helpers.segment.js:1645
    at _cached (helpers.segment.js:1685)
    at Object.get (helpers.segment.js:1644)
    at toRaw (reactivity.esm-bundler.js:698)
    at toRaw (reactivity.esm-bundler.js:698)
Promise.then (async)
queueFlush @ runtime-core.esm-bundler.js:286
queueCb @ runtime-core.esm-bundler.js:308
queuePreFlushCb @ runtime-core.esm-bundler.js:311
scheduler @ runtime-core.esm-bundler.js:2105
run @ reactivity.esm-bundler.js:183
trigger @ reactivity.esm-bundler.js:189
set value @ reactivity.esm-bundler.js:730
show @ vuesax3.common.js:57048
toggle @ vuesax3.common.js:57052
callWithErrorHandling @ runtime-core.esm-bundler.js:154
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:163
invoker @ runtime-dom.esm-bundler.js:308
chart.esm.js:5872 Uncaught TypeError: Cannot read property 'includes' of undefined
    at eventFilter (chart.esm.js:5872)
    at Array.filter (<anonymous>)
    at PluginService.notify (chart.esm.js:4776)
    at Chart.notifyPlugins (chart.esm.js:5854)
    at Chart._eventHandler (chart.esm.js:5873)
    at listener (chart.esm.js:5759)
    at Chart.event (chart.esm.js:3092)
    at helpers.segment.js:28
eventFilter @ chart.esm.js:5872
notify @ chart.esm.js:4776
notifyPlugins @ chart.esm.js:5854
_eventHandler @ chart.esm.js:5873
listener @ chart.esm.js:5759
event @ chart.esm.js:3092
(anonymous) @ helpers.segment.js:28
requestAnimationFrame (async)
(anonymous) @ helpers.segment.js:26
chart.esm.js:5872 Uncaught TypeError: Cannot read property 'includes' of undefined
    at eventFilter (chart.esm.js:5872)
    at Array.filter (<anonymous>)
    at PluginService.notify (chart.esm.js:4776)
    at Chart.notifyPlugins (chart.esm.js:5854)
    at Chart._eventHandler (chart.esm.js:5873)
    at listener (chart.esm.js:5759)
    at Chart.event (chart.esm.js:3092)
    at helpers.segment.js:28
eventFilter @ chart.esm.js:5872
notify @ chart.esm.js:4776
notifyPlugins @ chart.esm.js:5854
_eventHandler @ chart.esm.js:5873
listener @ chart.esm.js:5759
event @ chart.esm.js:3092
(anonymous) @ helpers.segment.js:28
requestAnimationFrame (async)
(anonymous) @ helpers.segment.js:26

For now, going back to 0.2.0 !!! And I am in Vue 3

Yeah I need to put my head on it I don't have much time for now, reverting to current behaviour

It seems to not be as simple at wrapping it in ref in Vue3 :(

@victorgarciaesgi It would be a much needed thing tho. Maybe you can expose an event on the component and emit the chart with an event every time it updates. I can bind to it with a v-model and then It would be good.

@TheCelebrimbor I made a temporary workaround with the emit in 0.2.6
There where already events chart:render chart:update and chart:destroy with chartInstance as payload!

Also another question, are you using Vue 3 with Vite.js or just via vue-cli and Webpack 5?

Oh!, super easy to miss because it is not in the readme. Will check it out asap.

I use Vue 3 with webpack 5.

You're right sorry I will specify them in the docs! :)

The bug seems to be coming from chartjs when chartInstance is reactive chartjs/Chart.js#8970

@victorgarciaesgi If you can give a small example of accessing those events in Vue 3 it would be great as well.

I am currently doing this
<component @chart:render="newChartInstance($event)" ref="chartRef" :is="chartComponent" :data="internalData" />

The event never fires. Hmmm......

Never mind! Stoopid mistake :D. It works for now !! thank you so much

You're sure? Because for me the @chart:render is not firing either aha

I bound to chart:update like this

<component @chart:update="chartInstance = $event"

seems to work for me. :)

UPDATE :

Exporting bar charts works, but Pie does not. Fails somewhere in charts.js. Bummer !! @victorgarciaesgi

@TheCelebrimbor hmm what's the error for Pie ? :(

@victorgarciaesgi Seems to work now. I ended up binding on both the render and update events.
The actual error was that the canvas member of the instance was null after switching chart type from bar to pie.

Many thanks for all the help! I think we can fix 0.2.8 as okay for now.

Oh you mean changing the type of the Chart dynamicaly? Maybe add a key to your dynamic component.
You're welcome thanks for reporting the bugs! :)

@TheCelebrimbor Just so you know, chartInstance is now accessible by ref, I managed to make it reactive :)