Chartjs tooltips are displayed across all charts when hovering over a single chart

Currently, I am utilizing ChartJS in conjunction with angular. I successfully implemented a vertical line on my chart when hovering by following the example provided at How to render a vertical line on hover in chartjs.

Now, I am seeking examples for creating a curved line chart where the X-axis shares a common date range across all charts within the DOM, while the Y-axis values differ. Ideally, hovering over any chart would trigger a hover effect on all available charts, displaying a vertical line similar to the above example, along with tooltips.

Answer №1

    tooltips: {
      mode: 'x-axis'
    },

Based on my understanding of your request, this code should fulfill your needs.

Answer №2

Check out this jsfiddle for assistance:

https://jsfiddle.net/vikas12118/k4oveLsb/

 var charts = [];

$(document).ready(function () {

    Chart.defaults.LineWithLine = Chart.defaults.line;
    Chart.controllers.LineWithLine = Chart.controllers.line.extend({
        draw: function(ease) {
            if (charts) {
                for (var i = 0; i < charts.length; i++) {
                    charts[i].tooltip._active = [];
                    charts[i].tooltip.update(true);
                    charts[i].draw();
                }
            }
            Chart.controllers.line.prototype.draw.call(this, ease);

            if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
                var activePoint = this.chart.tooltip._active[0],
                    ctx = this.chart.ctx,
                    x = activePoint.tooltipPosition().x,
                    topY = this.chart.scales['y-axis-0'].top,
                    bottomY = this.chart.scales['y-axis-0'].bottom;

                
                ctx.save();
                ctx.beginPath();
                ctx.moveTo(x, topY);
                ctx.lineTo(x, bottomY);
                ctx.lineWidth = 2;
                ctx.strokeStyle = '#07C';
                ctx.stroke();
                ctx.restore();
                if(charts)
                {
                    showTooltip(chart1.chart.tooltip._active[0]._index);

                }
            }
        }
    });



    var ctx1 = document.getElementById('myChart1').getContext('2d');
    var chart1 = new Chart(ctx1, {
        type: 'LineWithLine',
        data: {
            labels: ['Segment 1', 'Segment 2', 'Segment 3','Segment 4','Segment 5','Segment 6','Segment 7','Segment 8','Segment 9','Segment 10','Segment 11','Segment 12'],
            datasets: [{
                lineTension: 0,
                backgroundColor: "rgb(34,139,34)",
                borderColor: "rgb(34,139,34)",
                data: [14, 19, 20, 10, 6, 15, 8, 27, 25, 14, 36, 22],
                fill: false,
                pointRadius: 1.5,
                pointHoverRadius: 1,
                borderWidth :1.5
            }],
        },
        options: {
            maintainAspectRatio: false,
            responsive: false,
          
            hover: {
                mode: 'index',
                intersect: false,
            },
            title: {
                display: true,
                text: ''
            },
            legend: {
                display: false
            },
            tooltips: {
                mode: 'index',
                
                intersect: false,
            },
        }
    });


     var ctx2 = document.getElementById('myChart2').getContext('2d');
    Chart.defaults.LineWithLine = Chart.defaults.line;
    Chart.controllers.LineWithLine = Chart.controllers.line.extend({
        draw: function(ease) {
            Chart.controllers.line.prototype.draw.call(this, ease);

            if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
                var activePoint = this.chart.tooltip._active[0],
                    ctx = this.chart.ctx,
                    x = activePoint.tooltipPosition().x,
                    topY = this.chart.scales['y-axis-0'].top,
                    bottomY = this.chart.scales['y-axis-0'].bottom;

               
                ctx.save();
                ctx.beginPath();
                ctx.moveTo(x, topY);
                ctx.lineTo(x, bottomY);
                ctx.lineWidth = 2;
                ctx.strokeStyle = '#07C';
                ctx.stroke();
                ctx.restore();
            }
        }
    });

    var chart = new Chart(ctx2, {
        type: 'LineWithLine',
        data: {
            labels: ['Segment 1', 'Segment 2', 'Segment 3','Segment 4','Segment 5','Segment 6','Segment 7','Segment 8','Segment 9','Segment 10','Segment 11','Segment 12'],
            datasets: [{
                lineTension: 0,
                backgroundColor: "rgb(34,139,34)",
                borderColor: "rgb(34,139,34)",
                data: [14, 11, 10, 20, 20, 15, 25, 15, 13, 14, 16, 8],
                fill: false,
                pointRadius: 1.5,
                pointHoverRadius: 1,
                borderWidth :1.5
            }],
        },
        options: {
            maintainAspectRatio: false,
            responsive: false,
            title: {
                display: true,
                text: ''
            },
            legend: {
                display: false
            },
            tooltips: {
                mode: 'index',
                
                intersect: false,
            },
        }

    });

    charts.push(chart)

});


function showTooltip(index) {
    if (Array.isArray(charts) && charts.length) {
        for (var i = 0; i < charts.length; i++) {
            var segment = charts[i].getDatasetMeta(0).data[index];
            charts[i].tooltip._active = [segment];
            charts[i].tooltip.update(true);
            charts[i].draw();
        }
    }
}

Find the html content below

<div>
<canvas style="width: 800px" height="300px" id="myChart1"></canvas></div>
<div>
  <canvas style="width: 800px" height="300px" id="myChart2"></canvas></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>

Answer №3

If you're a developer working on projects using React, chartjs, and react-chartjs-2, and you want to build a dashboard with synchronized tooltips, check out this helpful example. I've even integrated a zoom plugin for easy click-and-drag zoom functionality.

https://example.com/react-chartjs-synchronized-tooltips-zoom

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

Sequelize throws an error stating 'Model is not defined' when trying to establish a relationship across multiple databases

I am in the process of creating a separate sequelize instance for each database. In some cases, tables in DB1 have relationships with tables in DB2, and vice versa. One such relationship is DB1.Utilisateur.contenuProvenance_id => DB2.Contenu.id and DB2. ...

What are the drawbacks of setting data from computed properties?

When working with vuex, I often come across a scenario where I receive an object like the following: user: {name: 'test'} In my app.vue file, I access this object using this.$store.getters.user computed: { user: function() { let user ...

How can we ensure that a child directive in AngularJS shares the same data as its parent?

My child directive needs access to the same data as its parent pages. What would be the most effective method for sharing this data? Should the child directive fetch the data separately, or should the parent send it through attributes? ...

Jasmine's capability to test method logic that executes following the resolution of a returned promise

I am looking to test a JavaScript method that I have written. Here is a simplified pseudo code representation of it: $scope.savePerson = function(){ Person.create($scope.person).then(function(newPerson){ if($scope.person.org){ ...

Trustpilot Authentication Error: Grant_type Not Recognized

I am attempting to utilize the Trustpilot API for sending email review invitations. Before making the call, I need to obtain an access token as per Trustpilot's documentation. However, when implementing the function below, I am encountering an error i ...

What is causing the form validation lines to not save and appear after I refresh the page?

Having trouble with the append element in my JavaScript code. Below is the JS file and the corresponding HTML file. JavaScript file: var ck_name = /^[A-Za-z0-9 ]{3,20}$/; var ck_email = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*& ...

Ways to retrieve an element from an array

I need help finding the right way to retrieve the value of the message "Meeting 9943...is not found or has expired". Here's what I tried: if (response.data.status == 404) { angular.element(document.getElementById("msg")).css("color", "red"); ...

How does Backbone.js tackle error handling when receiving messages from Rails?

Can anyone using backbone.js lend a hand? How can error messages from a rails app be encoded when integrating with backbone.js? For instance, how should flash messages like "record not found" be handled? While errors are usually defined on the client sid ...

Advancing the utilization of custom Angular input fields

I've developed a unique Angular input element that utilizes a textarea as its primary input field. Is there a way for me to pass along the enter key event to the main form? ...

Analyzing the differences in environment management between express and dotenv

Lately, I've noticed an abundance of tutorials and articles discussing NodeJS and the dotenv library. One common practice that keeps coming up is defining an ENV_MODE=development variable within the config.env file. However, it got me thinking - does ...

Unraveling the Distinctions: Identifying an Admin vs. a User within the API

When working with the express framework, I encounter a situation where I need to restrict access to certain API endpoints. For example, I have this line in the API: router.delete('/user',(req, res) => { //deleting...} Now, I want only an Adm ...

Tips for dividing an array based on a defined regex pattern in JavaScript

I want to split a string of text into an array of sentences while preserving the punctuation marks. var text = 'This is the first sentence. This is another sentence! This is a question?' var splitText = text.split(/\b(?<=[.!?])/); split ...

What is the best way to keep a div element fixed on the page no matter where you scroll?

For example: I have an extensive inventory of items, and as I hover my mouse over each item, a corresponding picture appears in this section. The div stays fixed in place regardless of scrolling. It works similar to a frame. ...

What is the correct way to use getServerSideProps?

Lately, I've been exploring the world of web development by creating a web app using NextJS. While I have some knowledge of the basics in this field, I found myself a bit lost when working with NextJS since I hadn't worked with React before. One ...

Trigger a notification based on the selected choice

Here is some sample HTML code: <div id="hiddenDiv" style="display: none;"> <h1 id="welcomehowareyou">How are you feeling today?</h1> <select name="mood" id="mood"> <option value="" disabled selected>How are you feeling?</o ...

Does Angular trigger an HTTP request when a variable's scope is updated?

Is it necessary to manually call the http get request in my Angular script when sending variables to the server, or will the request be triggered automatically if the sending variable changes? Thank you. Updated code snippet from my controller: $scope.s ...

When using Firestore in Android, I encounter a nodejs error regarding headers being sent prematurely

Currently, I am utilizing a webview in order to display content from a nodejs server. While requesting a page works as expected, accessing firestore results in an error where it seems like nodejs is attempting to resend the page. Below is the code for an a ...

Javascript code that ensures a popup only appears one time

As I create a static website without server-side functionality, my options are limited to HTML, CSS, and a few scripts. Incorporated into each page is a popup script that I designed using JavaScript: b = false; if (!b) { window.accept(); } function ...

It is possible that an infinite loop has occurred, as the program has now exceeded

In my project block on this sandbox, I have utilized tools like cherrio, https://cors-anywhere.herokuapp.com/, axios along with custom functions to navigate through pagination, extract data using web scraping techniques, and store the extracted data in an ...

What is the best way to prioritize a non-submit button over a submit button in material-ui?

I am facing an issue with a form on my website. Whenever I press the enter key, the form is automatically submitted. Everything seems to be working fine so far. However, there is a specific scenario where if a user selects a certain option in the form, it ...