How to show the value of each element when hovering

vbernal

I am new to D3.js and have created a graph that shows the sales history of some sellers.

In the table below shows the total sales result in the year, in the graph shows the monthly evolution of sales, when I hover under each circle I want to show the amount that sold in the respective month.

But it is always showing the same values (the values are being shown at the top of the chart).

    //#region Criando Tabela de Vendedores
    var newMapVendedores = [
        {
            "vendnm": "CHARNECA",
            "Vendas_Ano": 236009.2299999998,
            "Vendas_Ant": 282753.77999999997
        },
        {
            "vendnm": "JOÃO LUIS",
            "Vendas_Ano": 257733.04999999996,
            "Vendas_Ant": 332119.31
        },
    ]

    $(document).ready(function () {
        $("#tableVendedores").append('<tfoot><th></th><th></th><th></th></tfoot>');
        var table = $('#tableVendedores').DataTable({
            "data": newMapVendedores,
            "columns": [
                { "data": "vendnm", title: 'Vendedor' },
                { "data": "Vendas_Ano", title: 'Vendas Ano' },
                { "data": "Vendas_Ant", title: 'Vendas Ant' },
            ],
            "bLengthChange": false,
            "bPaginate": false,
            "bFilter": false,
            "info": false,
        });

        $('#tableVendedores').on('click', 'tr', function () {
            var data = table.row(this).data();
        });
    });

    //#endregion

    //#region GRÁFICO         

    var codes = ["VENDAS_ANO", "VENDAS_ANT"];
    $('span.values').html(codes.join(', '));

    modalitySelected = document.querySelector('input[name=modality-selector]:checked').value;

    var data = null;
    var filtered_data = null;

    var margin = { top: 30, right: 20, bottom: 50, left: 50 };
    var width = 600 - margin.left - margin.right;
    var height = 350 - margin.top - margin.bottom;
    var duration = 250;

    var lineOpacity = "0.25";
    var lineOpacityHover = "0.85";
    var otherLinesOpacityHover = "0.1";
    var lineStroke = "1.5px";
    var lineStrokeHover = "2.5px";

    var circleOpacity = '0.85';
    var circleOpacityOnLineHover = "0.25";
    var circleRadius = 3;
    var circleRadiusHover = 6;

    var month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

    var x = d3.scaleBand().range([0, width]).domain(month).padding(1);
    var y = d3.scaleLinear().range([height, 0]).domain([0, 65000]);

    var color = d3.scaleOrdinal(d3.schemeCategory10);

    var xAxis = d3.axisBottom(x).ticks(12);
    var yAxis = d3.axisLeft(y);

    var svg = d3.select("#line-chart-container")
        .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var g = null;

    var line = d3.line()
        .x(function (d) {
            return x(d.month);
        })
        .y(function (d) {
            return y(d.value);
        });
    // .curve(d3.curveBasis);

    let lines = svg.append('g')
        .attr('class', 'lines');

    var mouseG = svg.append("g") // this the black vertical line to folow mouse
        .attr("class", "mouse-over-effects");

    mouseG.append("path")
        .attr("class", "mouse-line")
        .style("stroke", "black")
        .style("stroke-width", "1px")
        .style("opacity", "0");

    // get data
    d3.queue()
        .defer(d3.json, 'http://www.json-generator.com/api/json/get/cjsmAgXIVu?indent=2')
        .await(makeLineChart);

    function makeLineChart(error, data) {

        if (error) {
            console.log(error);
        }

        color.domain(d3.keys(data[0])
            .filter(function (key) {
                return key == "CODE";
            })
        );

        createAxis();
        updateChart(data);

        // radio button change
        d3.selectAll("input[name='modality-selector']")
            .on("change", function () {
                modalitySelected = document.querySelector('input[name=modality-selector]:checked').value;
                clearChart();
                createAxis();
                updateChart(data);
            });

    } // end makeLineChart function

    /**
     * Create (if is the firts time) or updates the line chart, 
     * based on radio button selection.
     */
    function updateChart(data) {

        // filter data
        filtered_data = data.filter(function (d) {
            return d.MODALITY == modalitySelected && codes.includes(d.CODE);
        });

        // first we need to corerce the data into the right formats
        filtered_data = filtered_data.map(function (d) {
            return {
                code: d.CODE,
                month: d.MONTH,
                modality: d.MODALITY,
                value: +d.VALUE
            };
        });

        filtered_data = d3.nest()
            .key(function (d) {
                return d.code;
            })
            .entries(filtered_data);

        var codesArray = svg.selectAll(".code")
            .data(filtered_data, function (d) {
                return d.key;
            })
            .enter()
            .append("g")
            .attr("class", "code")
            .on("mouseover", function (d, i) {
                codesArray.append("text")
                    .attr("class", "title-text")
                    .style("fill", color(d.key))
                    .text('')
                    .attr("text-anchor", "middle")
                    .attr("x", 200)
                    .attr("y", 20);
            })
            .on("mouseout", function (d) {
                codesArray.select(".title-text").remove();
            })

        codesArray.append("path")
            .attr("class", "line")
            .attr("d", function (d) {
                // console.log(d)
                return line(d.values);
            })
            .style("stroke", function (d) {
                return color(d.key);
            })
            .style('opacity', lineOpacity)
            .on("mouseover", function (d) {
                d3.selectAll('.line')
                    .style('opacity', otherLinesOpacityHover);
                d3.selectAll('.circle')
                    .style('opacity', circleOpacityOnLineHover);
                d3.select(this)
                    .style('opacity', lineOpacityHover)
                    .style("stroke-width", lineStrokeHover)
                    .style("cursor", "pointer");
            })
            .on("mouseout", function (d) {
                d3.selectAll(".line")
                    .style('opacity', lineOpacity);
                d3.selectAll('.circle')
                    .style('opacity', circleOpacity);
                d3.select(this)
                    .style("stroke-width", lineStroke)
                    .style("cursor", "none");
            });

        /* Add circles in the line */
        codesArray.selectAll("circle-group")
            .data(filtered_data, function (d) {
                return d.key;
            })
            .enter()
            .append("g")
            .style("fill", function (d, i) {
                return color(d.key);
            })
            .on("mouseover", function (d, i) {
                d3.select(this)
                    .style("cursor", "pointer")
                    .append("text")
                    .attr("class", "text")
                    .text(d.values[i].value)
                    .attr("x", d => x(d.key) + 5)
                    .attr("y", d => y(d.value) + 10);
            })
            .on("mouseout", function (d) {
                codesArray.select(".text").remove();
            })
            .selectAll("circle")
            .data(d => d.values).enter()
            .append("g")
            .attr("class", "circle")
            .append("circle")
            .attr("cx", function (d) {
                return x(d.month)
            })
            .attr("cy", d => y(d.value))
            .attr("r", circleRadius)
            .style('opacity', circleOpacity)
            .on("mouseover", function (d) {
                d3.select(this)
                    .transition()
                    .duration(duration)
                    .attr("r", circleRadiusHover);
            })
            .on("mouseout", function (d) {
                d3.select(this)
                    .transition()
                    .duration(duration)
                    .attr("r", circleRadius);
            });

    }

    function createAxis() {

        g = svg.append("g")
            .attr("class", "chartGroup")

        g.append("g")
            .attr("class", "axis x")
            .attr("transform", "translate(0, " + height + ")")
            .call(xAxis);

        g.append("g")
            .attr("class", "axis y")
            .call(yAxis);
    }

    /**
     * Remove old chart (axis and lines).
     */
    function clearChart() {
        d3.select(".chartGroup").remove();
        d3.selectAll(".code").remove();
    }

    //#endregion
<head>
    <meta charset="utf-8">
    <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.css">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
        integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
        integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
        crossorigin="anonymous"></script>

    <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
    <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
    <script src="https://d3js.org/topojson.v2.min.js"></script>
    <script type="text/javascript" charset="utf8"
        src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.js"></script>
    <title>Index 9</title>
</head>

<style>
    svg {
        font-family: Sans-Serif, Arial;
    }

    .line {
        stroke-width: 1.5;
        fill: none;
    }

    .axis path {
        stroke: black;
    }

    .text {
        font-size: 12px;
    }

    .title-text {
        font-size: 12px;
    }

    table {
        font-family: Arial, Helvetica, sans-serif;
        border-collapse: collapse;
        font-size: 12px !important;
        margin-left: 10px;
        margin-top: 10px;
        /* width: 300px !important; */
    }

    .table td {
        padding: .0rem;
    }

    tr {
        line-height: 25px;
    }

    .axis path,
    .axis line {
        fill: none;
        stroke: grey;
        stroke-width: 1;
        shape-rendering: crispEdges;
    }

    th,
    td {
        border: 1px solid #cccccc;
        padding: 0px;
        text-align: center;
    }

    input {
        visibility: hidden;
    }

    label {
        cursor: pointer;
        margin-bottom: .0rem;
    }

    hr {
        margin-top: -5px;
        border-width: 1px;
        border-color: black;
    }
</style>

<body>

    <div style="width: 600px; margin-left: 10px;">
        <div id="line-chart-container"></div>
        <hr>
    <div style="width: 600px;" id="modality-selector-container">
        <form id="modality-selector">
            <div class="row table">
                <div class="col-6">
                    <h7 style="margin-left: 10px;">Sales</h7>
                    <table id="tableSales" class="table table-hover">
                        <thead>
                            <tr>
                                <th>Sale</th>
                                <th>Current Year</th>
                                <th>Last Year</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>
                                    <input type="radio" name="modality-selector" id="rb-charneca" value="charneca"
                                        checked />
                                    <label for="rb-charneca">CHARNECA</label>
                                </td>
                                <td>236.009,23</td>
                                <td>282.753,78</td>
                            </tr>
                            <tr>
                                <td>
                                    <input type="radio" name="modality-selector" id="rb-joaoluis"
                                        value="joaoluis" />
                                    <label for="rb-joaoluis">JOÃO LUIS</label>
                                </td>
                                <td>257.733,05</td>
                                <td>332.119,31</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </form>
    </div>
</div>
    </div>
</body>

As you can see, hovering over circles always shows the same values. Can you help me fix this?

Thank you very much in advance.

Gerardo Furtado

You are attaching the mouseover listener to the groups, hoping that the index i could give you the circle:

.on("mouseover", function (d, i) {
    d3.select(this)
        .append("text")
        .text(d.values[i].value)
        //etc...

However, that i is the index of the groups, not of the circles, and you have just two groups, with indices 0 and 1.

The simplest solution is attaching the listener to the circles themselves. Here is your code with that change:

//#region Criando Tabela de Vendedores
var newMapVendedores = [{
    "vendnm": "CHARNECA",
    "Vendas_Ano": 236009.2299999998,
    "Vendas_Ant": 282753.77999999997
  },
  {
    "vendnm": "JOÃO LUIS",
    "Vendas_Ano": 257733.04999999996,
    "Vendas_Ant": 332119.31
  },
]

$(document).ready(function() {
  $("#tableVendedores").append('<tfoot><th></th><th></th><th></th></tfoot>');
  var table = $('#tableVendedores').DataTable({
    "data": newMapVendedores,
    "columns": [{
        "data": "vendnm",
        title: 'Vendedor'
      },
      {
        "data": "Vendas_Ano",
        title: 'Vendas Ano'
      },
      {
        "data": "Vendas_Ant",
        title: 'Vendas Ant'
      },
    ],
    "bLengthChange": false,
    "bPaginate": false,
    "bFilter": false,
    "info": false,
  });

  $('#tableVendedores').on('click', 'tr', function() {
    var data = table.row(this).data();
  });
});

//#endregion

//#region GRÁFICO         

var codes = ["VENDAS_ANO", "VENDAS_ANT"];
$('span.values').html(codes.join(', '));

modalitySelected = document.querySelector('input[name=modality-selector]:checked').value;

var data = null;
var filtered_data = null;

var margin = {
  top: 30,
  right: 20,
  bottom: 50,
  left: 50
};
var width = 600 - margin.left - margin.right;
var height = 350 - margin.top - margin.bottom;
var duration = 250;

var lineOpacity = "0.25";
var lineOpacityHover = "0.85";
var otherLinesOpacityHover = "0.1";
var lineStroke = "1.5px";
var lineStrokeHover = "2.5px";

var circleOpacity = '0.85';
var circleOpacityOnLineHover = "0.25";
var circleRadius = 3;
var circleRadiusHover = 6;

var month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

var x = d3.scaleBand().range([0, width]).domain(month).padding(1);
var y = d3.scaleLinear().range([height, 0]).domain([0, 65000]);

var color = d3.scaleOrdinal(d3.schemeCategory10);

var xAxis = d3.axisBottom(x).ticks(12);
var yAxis = d3.axisLeft(y);

var svg = d3.select("#line-chart-container")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var g = null;

var line = d3.line()
  .x(function(d) {
    return x(d.month);
  })
  .y(function(d) {
    return y(d.value);
  });
// .curve(d3.curveBasis);

let lines = svg.append('g')
  .attr('class', 'lines');

var mouseG = svg.append("g") // this the black vertical line to folow mouse
  .attr("class", "mouse-over-effects");

mouseG.append("path")
  .attr("class", "mouse-line")
  .style("stroke", "black")
  .style("stroke-width", "1px")
  .style("opacity", "0");

// get data
d3.queue()
  .defer(d3.json, 'http://www.json-generator.com/api/json/get/cjsmAgXIVu?indent=2')
  .await(makeLineChart);

function makeLineChart(error, data) {

  if (error) {
    console.log(error);
  }

  color.domain(d3.keys(data[0])
    .filter(function(key) {
      return key == "CODE";
    })
  );

  createAxis();
  updateChart(data);

  // radio button change
  d3.selectAll("input[name='modality-selector']")
    .on("change", function() {
      modalitySelected = document.querySelector('input[name=modality-selector]:checked').value;
      clearChart();
      createAxis();
      updateChart(data);
    });

} // end makeLineChart function

/**
 * Create (if is the firts time) or updates the line chart, 
 * based on radio button selection.
 */
function updateChart(data) {

  // filter data
  filtered_data = data.filter(function(d) {
    return d.MODALITY == modalitySelected && codes.includes(d.CODE);
  });

  // first we need to corerce the data into the right formats
  filtered_data = filtered_data.map(function(d) {
    return {
      code: d.CODE,
      month: d.MONTH,
      modality: d.MODALITY,
      value: +d.VALUE
    };
  });

  filtered_data = d3.nest()
    .key(function(d) {
      return d.code;
    })
    .entries(filtered_data);

  var codesArray = svg.selectAll(".code")
    .data(filtered_data, function(d) {
      return d.key;
    })
    .enter()
    .append("g")
    .attr("class", "code")
    .on("mouseover", function(d, i) {
      codesArray.append("text")
        .attr("class", "title-text")
        .style("fill", color(d.key))
        .text('')
        .attr("text-anchor", "middle")
        .attr("x", 200)
        .attr("y", 20);
    })
    .on("mouseout", function(d) {
      codesArray.select(".title-text").remove();
    })

  codesArray.append("path")
    .attr("class", "line")
    .attr("d", function(d) {
      // console.log(d)
      return line(d.values);
    })
    .style("stroke", function(d) {
      return color(d.key);
    })
    .style('opacity', lineOpacity)
    .on("mouseover", function(d) {
      d3.selectAll('.line')
        .style('opacity', otherLinesOpacityHover);
      d3.selectAll('.circle')
        .style('opacity', circleOpacityOnLineHover);
      d3.select(this)
        .style('opacity', lineOpacityHover)
        .style("stroke-width", lineStrokeHover)
        .style("cursor", "pointer");
    })
    .on("mouseout", function(d) {
      d3.selectAll(".line")
        .style('opacity', lineOpacity);
      d3.selectAll('.circle')
        .style('opacity', circleOpacity);
      d3.select(this)
        .style("stroke-width", lineStroke)
        .style("cursor", "none");
    });

  /* Add circles in the line */
  codesArray.selectAll("circle-group")
    .data(filtered_data, function(d) {
      return d.key;
    })
    .enter()
    .append("g")
    .style("fill", function(d, i) {
      return color(d.key);
    })
    .selectAll("circle")
    .data(d => d.values).enter()
    .append("g")
    .attr("class", "circle")
    .append("circle")
    .attr("cx", function(d) {
      return x(d.month)
    })
    .attr("cy", d => y(d.value))
    .attr("r", circleRadius)
    .style('opacity', circleOpacity)
    .on("mouseover", function(d) {
      d3.select(this.parentNode)
        .style("cursor", "pointer")
        .append("text")
        .attr("class", "text")
        .text(d.value)
        .attr("x", d => x(d.month) + 10)
        .attr("y", d => y(d.value) - 10);
      d3.select(this)
        .transition()
        .duration(duration)
        .attr("r", circleRadiusHover);
    })
    .on("mouseout", function(d) {
    codesArray.select(".text").remove();
      d3.select(this)
        .transition()
        .duration(duration)
        .attr("r", circleRadius);
    });

}

function createAxis() {

  g = svg.append("g")
    .attr("class", "chartGroup")

  g.append("g")
    .attr("class", "axis x")
    .attr("transform", "translate(0, " + height + ")")
    .call(xAxis);

  g.append("g")
    .attr("class", "axis y")
    .call(yAxis);
}

/**
 * Remove old chart (axis and lines).
 */
function clearChart() {
  d3.select(".chartGroup").remove();
  d3.selectAll(".code").remove();
}

//#endregion
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.20/css/jquery.dataTables.css">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

  <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
  <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
  <script src="https://d3js.org/topojson.v2.min.js"></script>
  <script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.js"></script>
  <title>Index 9</title>
</head>

<style>
  svg {
    font-family: Sans-Serif, Arial;
  }
  
  .line {
    stroke-width: 1.5;
    fill: none;
  }
  
  .axis path {
    stroke: black;
  }
  
  .text {
    font-size: 12px;
  }
  
  .title-text {
    font-size: 12px;
  }
  
  table {
    font-family: Arial, Helvetica, sans-serif;
    border-collapse: collapse;
    font-size: 12px !important;
    margin-left: 10px;
    margin-top: 10px;
    /* width: 300px !important; */
  }
  
  .table td {
    padding: .0rem;
  }
  
  tr {
    line-height: 25px;
  }
  
  .axis path,
  .axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
  }
  
  th,
  td {
    border: 1px solid #cccccc;
    padding: 0px;
    text-align: center;
  }
  
  input {
    visibility: hidden;
  }
  
  label {
    cursor: pointer;
    margin-bottom: .0rem;
  }
  
  hr {
    margin-top: -5px;
    border-width: 1px;
    border-color: black;
  }
</style>

<body>

  <div style="width: 600px; margin-left: 10px;">
    <div id="line-chart-container"></div>
    <hr>
    <div style="width: 600px;" id="modality-selector-container">
      <form id="modality-selector">
        <div class="row table">
          <div class="col-6">
            <h7 style="margin-left: 10px;">Sales</h7>
            <table id="tableSales" class="table table-hover">
              <thead>
                <tr>
                  <th>Sale</th>
                  <th>Current Year</th>
                  <th>Last Year</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>
                    <input type="radio" name="modality-selector" id="rb-charneca" value="charneca" checked />
                    <label for="rb-charneca">CHARNECA</label>
                  </td>
                  <td>236.009,23</td>
                  <td>282.753,78</td>
                </tr>
                <tr>
                  <td>
                    <input type="radio" name="modality-selector" id="rb-joaoluis" value="joaoluis" />
                    <label for="rb-joaoluis">JOÃO LUIS</label>
                  </td>
                  <td>257.733,05</td>
                  <td>332.119,31</td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
      </form>
    </div>
  </div>
  </div>
</body>

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to show a single value when hovering a Multiline glyph in Bokeh?

how to show tooltip when hovering?

How would I show text inside a span tag when hovering over a different element?

How to show div when hovering dynamically a link?

How to use tailwindcss to change the color of each element when hovering over descendant elements

I need to show a element in a table when hovering another next to it with javascript

How can I make a element show when hovering over another element, and hide it if not. And make it take up space the entire time

How to change color of element when hovering over another element?

How to style the parent element when hovering a child element?

jQuery: How to hover a child of child element when hovering on the main element

How to show javadoc of a imported library when hovering on it's methods and classes?

how to show a content after and a tooltip when hovering over it?

How do I show data on one card when hovering and not on all?

How to show the dropdown when hovering over the dropdown list

How to change font family + background when hovering over each letter

How do I display the value of a heatmap element by hovering the cursor over it?

D3 - How can I show/hide a text element when hovering a circle element created from different attributes of the same data entry?

How to change color on every element in div when hovering?

How to stop the elements from growing when hovering over an element?

How to change opacity of child-element when hovering his parent

How to change CSS elements of an element when hovering on another

How to trigger two hovers when hovering over single element CSS

How to scroll up a div when hovering over another element

How can we extract particular elements value by using xpath when element value is different for each element

Keep hovering state of parent element when hovering child element

Show/Hide cascading menu while hovering element

How to change text-decoration to underline when hovering the a element, if the a element is below another element with position absolute?

How to show each element of array separately

How to show labels on x axis for each element?