{"id":12,"date":"2022-01-20T21:40:15","date_gmt":"2022-01-20T21:40:15","guid":{"rendered":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/?p=12"},"modified":"2022-01-20T21:40:15","modified_gmt":"2022-01-20T21:40:15","slug":"using-chart-js-with-vue-js-v3","status":"publish","type":"post","link":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/2022\/01\/20\/using-chart-js-with-vue-js-v3\/","title":{"rendered":"Using Chart.js with Vue.js v3"},"content":{"rendered":"\n<h3 class=\"wp-block-heading\">Introduction<\/h3>\n\n\n\n<p>I recently needed a way to integrate a charting utility into a Vue.js project of mine and needed to find a way to do so. I really enjoyed the flexibility of Chart.js, but at this time, there is no integrated implementation of Chart.js into v3 of Vue.js. I experimented with some npm packages with no luck. So it was time to get dirty and fake it until I made it work.<\/p>\n\n\n\n<p>In this post, I will be showing a quick way to make a Chart.js component that can react to props for re-usability multiple times in your Vue.js projects.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites <\/h3>\n\n\n\n<p>To complete this tutorial, you will need the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Node.js and NPM package manager installed locally<\/li><li>Basic Knowledge of Vue.js components (I recommend using the Vue CLI to create a project)<\/li><\/ul>\n\n\n\n<p>This tutorial is being prepared with Node v14.17.1, @vue\/cli 4.5.15, npm 8.3.1, and Chart.js 3.7.0.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1 &#8211; Creating Your Vue Project and Install Chart.js<\/h3>\n\n\n\n<p>Let&#8217;s create our project directory using Vue CLI and use default to use Vue 3<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ vue create vue-chart --default\n<\/code><\/pre>\n\n\n\n<p>Then let&#8217;s change to the directory. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd vue-chart\n<\/code><\/pre>\n\n\n\n<p>Now, we can install Chart.js into our project using npm package manager.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install chart.js\n<\/code><\/pre>\n\n\n\n<p>At this point, we have created our vue-chart sample project and installed our Chart.js dependencies. Let&#8217;s get to the fun work now!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2 &#8211; Create a Vue Chart Component<\/h3>\n\n\n\n<p>I will provide our sample data later in this tutorial, but lets immediately get into creating the Vue component that we can import to other components in our Vue application.<\/p>\n\n\n\n<p>Under your <code>src<\/code> directory, you will have a <code>components<\/code> directory. You might notice it has the default <code>HelloWorld.vue<\/code> file if you used the Vue CLI as before in step 1. In this folder, create the file <code>Chart.vue<\/code>.<\/p>\n\n\n\n<p>Now, we will want to properly format our component into what Vue likes to see including our <code>template<\/code> and <code>script<\/code> elements. We will also include the <code>canvas<\/code> element with a specific <code>id<\/code> that Chart.js relies on and import it into our component. It is also a good idea to wrap our canvas component into a div for Vue to properly operate. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;template&gt;\n &lt;div&gt;\n  &lt;canvas id=\"chart-example\"&gt;&lt;\/canvas&gt;\n &lt;\/div&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nimport Chart from 'chart.js\/auto';\n\nexport default {\n  name: \"Chart\"\n}\n&lt;\/script&gt;\n<\/code><\/pre>\n\n\n\n<p>At this point, you have created the base Vue component. Now what? Well, we will need to add just a few more lines to allow Chart.js to do its thing and Vue to accept props from parent components.<\/p>\n\n\n\n<p>Let&#8217;s first take care of props, Vue&#8217;s way of sending data to child components so we can make this truly reusable.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n&lt;template&gt;\n &lt;div&gt;\n  &lt;canvas id=\"chartexample\"&gt;&lt;\/canvas&gt;\n &lt;\/div&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nimport Chart from 'chart.js\/auto';\n\nexport default {\n  name: \"Chart\",\n  <span class=\"has-inline-color has-yellow-color\">props: &#091;'chartData']<\/span><span style=\"color:#00990d\" class=\"has-inline-color\">\n<\/span><span class=\"has-inline-color has-dark-gray-color\">}<\/span>\n&lt;\/script&gt;\n<\/code><\/pre>\n\n\n\n<p><code>chartData<\/code> will be our general prop that we import to provide Chart.js the data it would like to create our graphs. The power of usability!<\/p>\n\n\n\n<p>Now, our canvas chart element needs that linked to our prop. This is where a lot of functionally breaks down if we do not properly link them. For this, we are going to use vanilla JavaScript and DOM manipulation in conjunction with Vue&#8217;s <code>mounted <\/code>lifecycle hook to make sure it is updated when Vue renders our component instance.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n&lt;template&gt;\n &lt;div&gt;\n  &lt;canvas id=\"chart-example\"&gt;&lt;\/canvas&gt;\n &lt;\/div&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nimport Chart from 'chart.js\/auto';\n\nexport default {\n  name: \"Chart\",\n  <span class=\"has-inline-color has-dark-gray-color\">props: &#091;'chartData']<\/span><span class=\"has-inline-color has-yellow-color\">,<\/span>\n  <span class=\"has-inline-color has-yellow-color\">mounted() {\n    const chart = document.getElementById('chart-example');\n    new Chart(chart, this.chartData);<\/span>\n <span class=\"has-inline-color has-yellow-color\">}<\/span><span style=\"color:#00990d\" class=\"has-inline-color\">\n<\/span><span class=\"has-inline-color has-dark-gray-color\">}<\/span>\n&lt;\/script&gt;\n<\/code><\/pre>\n\n\n\n<p>Okay, we just added a lot there. What essentially is happening is during the <code>mounted<\/code> hook of Vue, the <code>chart<\/code> variable now points to our <code>canvas<\/code> element that Chart.js can use. This is all we have to do now for our component. If this is your first time making a Vue component, congrats! You just made your first reusable component in Vue! <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3 &#8211; Import Your Chart Component<\/h3>\n\n\n\n<p>At this point, we want to display our component on our Vue app. You will want to navigate to <code>App.vue <\/code>in the <code>src<\/code> directory. This is your main parent component if you are new to Vue. If you used Vue CLI, you will have a populated page. We do not need any of this. Let&#8217;s make some changes to App.vue by removing the &#8220;HelloWorld&#8221; component, import, and element to make sure we do not have any extraneous items.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;template&gt;\n  \n&lt;\/template&gt;\n\n&lt;script&gt;\n\n\nexport default {\n  name: 'App',\n  components: {\n    \n  }\n}\n&lt;\/script&gt;\n<\/code><\/pre>\n\n\n\n<p>Looks similar to our <code>Chart.vue<\/code> component base template right? Now let&#8217;s start importing our  <code>Chart.vue<\/code> component.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n&lt;template&gt;\n  <span class=\"has-inline-color has-yellow-color\">&lt;Chart\/&gt;<\/span>\n&lt;\/template&gt;\n\n&lt;script&gt;\n<span class=\"has-inline-color has-yellow-color\">import Chart from \"@\/components\/Chart\";<\/span>\n\nexport default {\n  name: 'App',\n  components: {\n    <span class=\"has-inline-color has-yellow-color\">Chart<\/span>\n  }\n}\n&lt;\/script&gt;\n<\/code><\/pre>\n\n\n\n<p>Awesome! You now imported your created <code>Chart.vue<\/code> component to your parent component. Time to give it some data to create a chart now!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4 &#8211; Feed Your Chart Some Data<\/h3>\n\n\n\n<p>You cannot have a chart without some data, so let&#8217;s build an object that we can feed our <code>Chart.vue<\/code> component to digest! <\/p>\n\n\n\n<p>For Chart.js, when you make a chart object, it requires an internal data object that has arguments that can be populated. In the interest of time, I would recommend going through the Chart.js documentation to learn more, but because we built our <span class=\"has-inline-color has-dark-gray-color\"><code>Chart.vue<\/code><\/span> component to be reusable, you can change anything! Line graph, bar graph, animated graph, doesn&#8217;t matter!<\/p>\n\n\n\n<p>Now let&#8217;s use Vue&#8217;s powerful data() property to store objects and return data in conjunction with v-bind to send this chart internal data object through our prop earlier. For our chart data, I am just going to use the provided <a rel=\"noreferrer noopener\" href=\"https:\/\/www.chartjs.org\/docs\/latest\/#creating-a-chart\" data-type=\"URL\" data-id=\"https:\/\/www.chartjs.org\/docs\/latest\/#creating-a-chart\" target=\"_blank\">example on Chart.js<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;template&gt;\n    &lt;Chart\/&gt;\n&lt;\/template&gt;\n\n&lt;script&gt;\nimport Chart from \"@\/components\/Chart\";\n\nexport default {\n  name: 'App',\n  components: {\n    Chart\n  },\n  <span class=\"has-inline-color has-yellow-color\">data() {\n    return {\n      chartObject: {\n        type: 'bar',\n        data: {\n          labels: &#091;'Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],\n          datasets: &#091;{\n            label: '# of Votes',\n            data: &#091;12, 19, 3, 5, 2, 3],\n            backgroundColor: &#091;\n              'rgba(255, 99, 132, 0.2)',\n              'rgba(54, 162, 235, 0.2)',\n              'rgba(255, 206, 86, 0.2)',\n              'rgba(75, 192, 192, 0.2)',\n              'rgba(153, 102, 255, 0.2)',\n              'rgba(255, 159, 64, 0.2)'\n            ],\n            borderColor: &#091;\n              'rgba(255, 99, 132, 1)',\n              'rgba(54, 162, 235, 1)',\n              'rgba(255, 206, 86, 1)',\n              'rgba(75, 192, 192, 1)',\n              'rgba(153, 102, 255, 1)',\n              'rgba(255, 159, 64, 1)'\n            ],\n            borderWidth: 1\n          }]\n        },\n        options: {\n          scales: {\n            y: {\n              beginAtZero: true\n            }\n          }\n        }\n      }\n    }\n  }<\/span>\n}\n&lt;\/script&gt;\n<\/code><\/pre>\n\n\n\n<p>And now, let&#8217;s use v-bind on our <code>&lt;Chart\/&gt;<\/code> tag. This will take our parent component data and give it to our <code>Chart.vue<\/code> component. Essentially, the parent has the data, but doesn&#8217;t know how to make a chart; the child knows how to make a chart, but doesn&#8217;t have the data. We now get to combine them to complete it! (I am also going to wrap our Chart in a <code>&lt;div&gt;<\/code> so we can give it an inline style of<code> max-width<\/code> so our chart is manageable when we serve it.) <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n&lt;template&gt;\n  &lt;div style=\"max-width: 900px\"&gt;\n    &lt;Chart <span class=\"has-inline-color has-yellow-color\">:chart-data=\"chartObject\"<\/span>\/&gt;\n  &lt;\/div&gt;\n&lt;\/template&gt;<\/code><\/pre>\n\n\n\n<p>One thing to note if you are new to Vue bindings, our child element has the prop &#8220;chartData&#8221; if you remember from Step 2. How does this relate? Well, HTML inline attributes must be kebab-case so when you have to pass with a v-bind to a prop that is in the lowerCamelCase that Vue uses, Vue will automatically convert that from &#8220;chartData&#8221; to &#8220;chart-data&#8221; in this instance. Cool huh? More create and less syntax drama. <\/p>\n\n\n\n<p>Alright, last step is next. Let&#8217;s see that creation!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5 &#8211; Serve Your Chart!<\/h3>\n\n\n\n<p>At this point, everything will be connected and ready to serve! If you have a Vue background, you know the magic words, if not, go back to your terminal that has the project directory from Step 1 and enter the magic words.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ npm run serve\n<\/code><\/pre>\n\n\n\n<p>Open up a browser to see your Vue application. By default, Vue will serve locally at port 8080.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>http:&#047;&#047;localhost:8080\/<\/code><\/pre>\n\n\n\n<p>What you should see is this in your browser!<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5063\/files\/2022\/01\/chartjs-vue-tutorial.png\" alt=\"\" class=\"wp-image-18\" width=\"690\" height=\"347\" srcset=\"https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5063\/files\/2022\/01\/chartjs-vue-tutorial.png 912w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5063\/files\/2022\/01\/chartjs-vue-tutorial-300x151.png 300w, https:\/\/osu-wams-blogs-uploads.s3.amazonaws.com\/blogs.dir\/5063\/files\/2022\/01\/chartjs-vue-tutorial-768x387.png 768w\" sizes=\"auto, (max-width: 690px) 100vw, 690px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Our Vue application is alive! You have successfully made a reusable Vue component with Chart.js accepting any data prop you give it. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Conclusion<\/h3>\n\n\n\n<p>So what, you made a chart you might be thinking? Well, let me close on some hidden superpowers that your Chart component possesses. First, you get all the power of Chart.js that will not break as you build out your Vue application. It is isolated to its own component. Second, you can use Vue&#8217;s power of rendering to change the Chart without changing the web page! There are various conditions under which a component will re-render. I will link Michael Thiessen&#8217;s <a rel=\"noreferrer noopener\" href=\"https:\/\/michaelnthiessen.com\/force-re-render\/\" data-type=\"URL\" data-id=\"https:\/\/michaelnthiessen.com\/force-re-render\/\" target=\"_blank\">blog post<\/a> on this topic. It has a lot of information on this for re-rendering a component. It will work directly with this if you want to start building methods on your parent component to alter data, say for a dashboard of some sort. <\/p>\n\n\n\n<p>And there you have it! A quick and dirty way to integrate arguably the best chart Javascript library into your Vue.js 3 projects without Chart.js support out of the box! <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction I recently needed a way to integrate a charting utility into a Vue.js project of mine and needed to find a way to do so. I really enjoyed the flexibility of Chart.js, but at this time, there is no integrated implementation of Chart.js into v3 of Vue.js. I experimented with some npm packages with &hellip; <a href=\"https:\/\/blogs.oregonstate.edu\/stanleymohr\/2022\/01\/20\/using-chart-js-with-vue-js-v3\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Using Chart.js with Vue.js v3<\/span><\/a><\/p>\n","protected":false},"author":11911,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-12","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/posts\/12","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/users\/11911"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/comments?post=12"}],"version-history":[{"count":6,"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/posts\/12\/revisions"}],"predecessor-version":[{"id":19,"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/posts\/12\/revisions\/19"}],"wp:attachment":[{"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/media?parent=12"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/categories?post=12"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.oregonstate.edu\/stanleymohr\/wp-json\/wp\/v2\/tags?post=12"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}