Adding images to chart labels in vue-chartjs explained

I'm facing a challenge in adding flag icons below the country code labels, and I could really use some guidance.

Here is an image of the chart with my current code

The flag images I need to use are named BR.svg, FR.svg, and MX.svg, located under @/assets/icons/flags/

In my project, I am utilizing

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6117140421534f574f5053">[email protected]</a>
and
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="86f0f3e3abe5eee7f4f2ecf5c6b5a8b3a8b7">[email protected]</a>
. Below is my Chart.vue component:

<script>
import { Bar } from 'vue-chartjs'

export default {
  extends: Bar,
  data: () => ({
    chartdata: {
      labels: ['BR', 'FR', 'MX'],
      datasets: [
        {
          label: 'Lorem ipsum',
          backgroundColor: '#AF78D2',
          data: [39, 30, 30],
        }
      ]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      legend: {
        display: false,
      },
      tooltips: {
        "enabled": false
      },
      scales : {
        xAxes : [ {
            gridLines : {
                display : false
            }
        } ],
        yAxes: [{
          ticks: {
            beginAtZero: true,
            suggestedMin: 0,
            suggestedMax: 40,
            stepSize: 5,
          }
        }]
      },
      "hover": {
        "animationDuration": 0
      },
      "animation": {
        "duration": 1,
        "onComplete": function() {
          var chartInstance = this.chart,
          ctx = chartInstance.ctx;

          ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
          ctx.textAlign = 'center';
          ctx.textBaseline = 'bottom';

          this.data.datasets.forEach(function(dataset, i) {
            var meta = chartInstance.controller.getDatasetMeta(i);
            meta.data.forEach(function(bar, index) {
              var data = dataset.data[index] + '%';
              ctx.fillText(data, bar._model.x, bar._model.y - 5);
            });
          });
        }
      },
    }
  }),
  mounted () {
    this.renderChart(this.chartdata, this.options)
  }
}
</script>

The code snippet below is the closest solution I found after hours of searching. Unfortunately, integrating it into my existing code has proven challenging.

const labels = ['Red Vans', 'Blue Vans', 'Green Vans', 'Gray Vans'];
const images = ['https://i.stack.imgur.com/2RAv2.png', 'https://i.stack.imgur.com/Tq5DA.png', 'https://i.stack.imgur.com/3KRtW.png', 'https://i.stack.imgur.com/iLyVi.png'];
const values = [48, 56, 33, 44];

new Chart(document.getElementById("myChart"), {
  type: "bar",
  plugins: [{
    afterDraw: chart => {      
      var ctx = chart.chart.ctx; 
      var xAxis = chart.scales['x-axis-0'];
      var yAxis = chart.scales['y-axis-0'];
      xAxis.ticks.forEach((value, index) => {  
        var x = xAxis.getPixelForTick(index);      
        var image = new Image();
        image.src = images[index],
        ctx.drawImage(image, x - 12, yAxis.bottom + 10);
      });      
    }
  }],
  data: {
    labels: labels,
    datasets: [{
      label: 'My Dataset',
      data: values,
      backgroundColor: ['red', 'blue', 'green', 'lightgray']
    }]
  },
  options: {
    responsive: true,
    legend: {
      display: false
    },    
    scales: {
      yAxes: [{ 
        ticks: {
          beginAtZero: true
        }
      }],
      xAxes: [{
        ticks: {
          padding: 30
        }   
      }],
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>

When attempting to add the plugin code to my own, I encounter an error message stating that 'plugins' is already defined in props, but I haven't been able to resolve this issue. Any insights on implementing the afterDraw plugin into my code would be greatly appreciated.

Thank you in advance! :)

Answer №1

Within the mounted hook of your Vue component, you have the ability to invoke the addPlugin method (which must be executed before the renderChart method) in this manner:

this.addPlugin({
  id: 'image-label',
  afterDraw: (chart) => {      
      var ctx = chart.chart.ctx; 
      var xAxis = chart.scales['x-axis-0'];
      var yAxis = chart.scales['y-axis-0'];
      xAxis.ticks.forEach((value, index) => {  
        var x = xAxis.getPixelForTick(index);      
        var image = new Image();
        image.src = images[index],
        ctx.drawImage(image, x - 12, yAxis.bottom + 10);
      });      
    }
})

For further details, please refer to the documentation:

Answer №2

If you are using ChartJS version 4.0.1, make sure to include the following code snippet in your data:

data() {
    return {
        plugins: [{
            afterDraw: chart => {
                    const ctx = chart.ctx;
                    const xAxis = chart.scales['x'];
                    const yAxis = chart.scales['y'];
                    xAxis.ticks.forEach((value, index) => {
                        let x = xAxis.getPixelForTick(index);
                        ctx.drawImage(images[index], x - 12, yAxis.bottom + 10)
                    });
                }
        }],
        data: {...

Remember to use chart.ctx instead of chart.chart.ct and chart.scales['x'] instead of chart.scales['x-axis-0'].

Once you have included the plugins in your data, reference it in your Bar component like this:

<Bar :data="data" :options="options" :plugins="plugins"/>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilize axios-cache-interceptor to enforce caching of responses from axios

Is it possible to configure axios to always return a cached response with the help of axios-cache-interceptor? import axios from 'axios' import { setupCache } from 'axios-cache-interceptor' const axiosInstance = axios.create({ timeou ...

Keeping track of the toggle state using a cookie

While searching for a way to retain the toggle state, I stumbled upon js-cookie on GitHub. The documentation provides instructions on creating, reading, and deleting a cookie. However, an example would have been really helpful in enhancing my understanding ...

What is the reason behind the non-exportation of actions in Redux Toolkit for ReactJS?

Currently, I am utilizing @reduxjs/toolkit along with reactjs to create a shopping cart feature. However, I am encountering an issue when attempting to export actions from Cart.js and import them into other files like cart.jsx and header.jsx. The error mes ...

Turn off email alerts for items and folders in ALFRESCO 5.2

Here's a snippet of JS code I created to toggle notifications with a button click: (Action.min.js): var me = this, jsNode = record.jsNode, content = jsNode.isContainer ? "folder" : "document"; if (jsNode.hasAspect("cm:emailed") ...

Single array returned by observable

Issue: I am looking for a way to consolidate the multiple arrays returned individually into a single array. Solution: fetchAllRiders() { var distanceObs = Observable.create(observer => { this.http.get(this.API + '/driver/all').map(res = ...

Creating a layered image by drawing a shape over a photo in Ionic using canvas

While there are plenty of examples demonstrating how to draw on a canvas, my specific problem involves loading a photo into memory, adding a shape to exact coordinates over the photo, and then drawing/scaling the photo onto a canvas. I'm unsure of whe ...

How can I display all categories in a Radar chart using amcharts 5

I'm currently using React with amcharts to generate a Radar chart. The data I have is structured as an array of objects like this: { category: 'Something', value: 5 }. There are a total of 12 items in the data set. However, when plotting t ...

Implement React-intl into the designated placeholder within the object

Currently facing an issue with the const inputProps in my code. I attempted to integrate React-intl into the react-autosuggest placeholder input, but now the placeholder text displays as: [Object object]. The getStepContent function is defined as follow ...

Retrieve data from a text file using ajax and then return the string to an HTML document

Just starting out with ajax, I have a text file containing number values For example, in ids.txt, 12345 maps to 54321 12345,54321 23456,65432 34567,76543 45678,87654 56789,98765 Here is the Html code snippet I am using <html><body> < ...

Storing ajax data into a variable seems to be a challenge for me

I am facing an issue with my ajax call where I am receiving the data correctly, but I am unable to assign it to a local variable named item_price. The data that I am receiving can either be 100.00 or 115.25. Below is the snippet of my ajax code: $.ajax({ ...

Guide on how to switch a class on the body using React's onClick event

There's a button in my code that triggers the display of a modal-like div element. When this button is clicked, I aim to apply a class to the body element; then when the close button is clicked, I'll remove this class. I'm looking for guid ...

Adding JavaScript to dynamically loaded AJAX content

I'm new to AJAX and JavaScript and unsure of how to get it working. Here is the website: When you click on portfolio images, the details load via AJAX. I want to create a slideshow for projects with multiple full-sized images. However, due to the co ...

Reverse changes made to a massive object and then redo them

My current project requires the implementation of undo-redo functionality for a product. At the moment, I am managing a substantial Object retrieved from a MongoDB collection The structure is as follows: { cart:{ products:[ { name: " ...

Adjust the styling of the anchor tag within the selected div by utilizing jQuery

I am struggling with changing the color of a specific anchor tag when clicked inside a div with class .product_wishlist. Currently, all anchor tags within .pw div are changing colors. Is there a way to apply selected css only to the clicked element? Any he ...

Animating with React using the animationDelay style does not produce the desired effect

Is there a way to apply an animation to each letter in a word individually when hovering over the word? I want the animation to affect each letter with an increasing delay, rather than all at once. For example, if scaling each letter by 1.1 is the animatio ...

A beginner's guide to efficiently indexing tables in AngularJS

Having Trouble with ng-repeat Indexing <tr ng-repeat="Ward in Wardresult "> <td>{{$index + 1}}</td> ...................... some column ....................... </tr> Although, the output ...

Tips for maintaining video height consistency while adjusting its attributes

When you click on a button, the video's poster and src attributes change. However, after clicking, the video height briefly becomes 0, causing an unsightly effect on the entire page. How can this be avoided? Please note - lorem.mp4 and ipsum.mp4 hav ...

Vue - The import statement cannot be used outside of a module context

I am currently working on developing a form that requires certain dependencies listed in the package.json file including vue, axios, and sweetalert. "dependencies": { "axios": "^0.19.0", "vue": "^2.6.10" ...

Ways to determine the current active tab in React are:

Currently, I am facing an issue with my code involving two tabs. Upon clicking on the second tab, I want to display a specific message. However, I am struggling to determine when the second tab is selected. The main problem lies in the fact that the selec ...

json How to retrieve the first index value in jQuery

As part of my Ajax loop, I am successfully generating JSON and iterating through the results. My goal is to extract only the first index value of JSON which is name. In jQuery, I have the following code: PHP $jsonRows[] = array( "name" => ...