victorgarciaesgi / vue-chart-3

📊 A simple wrapper around Chart.js 3 for Vue 2 & 3
https://vue-chart-3.netlify.app/
MIT License
310 stars 113 forks source link

Accessing the chartInstance for any processing purposes #4

Closed TheCelebrimbor closed 3 years ago

TheCelebrimbor commented 3 years ago

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!.

victorgarciaesgi commented 3 years ago

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 :)

victorgarciaesgi commented 3 years ago

I will add a section in the README for it!

TheCelebrimbor commented 3 years ago

@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

victorgarciaesgi commented 3 years ago

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

victorgarciaesgi commented 3 years ago

@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 :(

TheCelebrimbor commented 3 years ago

@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
TheCelebrimbor commented 3 years ago

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

victorgarciaesgi commented 3 years ago

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

victorgarciaesgi commented 3 years ago

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

TheCelebrimbor commented 3 years ago

@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.

victorgarciaesgi commented 3 years ago

@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!

victorgarciaesgi commented 3 years ago

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

TheCelebrimbor commented 3 years ago

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

I use Vue 3 with webpack 5.

victorgarciaesgi commented 3 years ago

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

victorgarciaesgi commented 3 years ago

The bug seems to be coming from chartjs when chartInstance is reactive https://github.com/chartjs/Chart.js/issues/8970

TheCelebrimbor commented 3 years ago

@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......

TheCelebrimbor commented 3 years ago

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

victorgarciaesgi commented 3 years ago

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

TheCelebrimbor commented 3 years ago

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

victorgarciaesgi commented 3 years ago

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

TheCelebrimbor commented 3 years ago

@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.

victorgarciaesgi commented 3 years ago

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! :)

victorgarciaesgi commented 3 years ago

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