Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I would like to show tooltip on hovering existing svg elements.

In the live example the elements to hover are created when binding data. In my case these elements exists already in DOM (circles). so I need to select them right after selectedElms.enter()

My question is how can I apply tip.show and tip.hide on circles ?

var data = [{
    train: 1
    train: 2
    train: 3
    train: 4
var svg = d3.select('svg')
var tip = d3.tip()
    .attr('class', 'd3-tip')
    .offset([-10, 0])
    .html(function(d) {
        return "<strong>Frequency:</strong> <span style='color:red'>" + d.train + "</span>";
svg.call(tip);
let selectedElms = d3.selectAll('circle').data(data, function(d) {
    if (d != undefined) {
        return d.train
console.log('hi')
selectedElms.enter().on('mouseover', tip.show).on('mouseout', tip.hide)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<!DOCTYPE html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"
></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<svg height="400" width="500">
  <circle data='1' cx="100" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="1"  />
  <circle data='2' cx="200" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="2" />
  <circle data='3' cx="300" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="3"  />
  <circle data='4' cx="400" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="4"  />
                @infodev You have to versions of included two versions of D3 in your snippet with the latter winning over the former. Your version of d3-tip doesn't seem to work with d3 v4. This may just be a copy-and-past error while creating the demo, though. Note, that I ditch v4 in favor of v3 in my answer. You may have to correct for that in your own code.
– altocumulus
                Oct 8, 2019 at 8:15
  • Like I mentioned in my answer to your first question on this topic, the key function is executed twice while matching data to DOM elements. To bind data to existing DOM elements you have to use the technique as laid out in Join existing elements of the DOM to data with d3.js. In your case the key function becomes

    .data(data, function(d) {
      return (d && d.train) || this.id;
    

    The first expression d && d.train checks if d refers to an actual value and, if true, evalutates to its property .train. This is the case while the key function is executed for each datum in the data argument. The second expression this.id is conditionally evaluated if d is undefined which is the case while the key function is executed for the selected, i.e. already existing, elements. If a match is found the respective datum is bound to the element.

  • You are only interested in updating elements which already exist in the DOM. For that reason you do not need to use the enter selection at all. The update selection which is returned by .data() will suffice. You can just drop the call to .enter().

  • Have a look at the following snippet to see it in action:

    var data = [{
        train: 1
        train: 2
        train: 3
        train: 4
    var svg = d3.select('svg')
    var tip = d3.tip()
        .attr('class', 'd3-tip')
        .offset([-10, 0])
        .html(function(d) {
            return "<strong>Frequency:</strong> <span style='color:red'>" + d.train + "</span>";
    svg.call(tip);
    let selectedElms = d3.selectAll('circle')
      .data(data, function(d) {
        return (d && d.train) || this.id;
    selectedElms
      .on('mouseover', tip.show)
      .on('mouseout', tip.hide);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
    <script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
    <svg height="400" width="500">
      <circle data='1' cx="100" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="1"  />
      <circle data='2' cx="200" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="2" />
      <circle data='3' cx="300" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="3"  />
      <circle data='4' cx="400" cy="110" r="40" stroke="black" stroke-width="3" fill="red" id="4"  />
                    I have a problem when I implement the solution on my real app. this.id does not exist ( Im using Angular )  Property 'id' does not exist on type 'Window'
    – infodev
                    Oct 8, 2019 at 8:14
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.