admin管理员组

文章数量:1403493

New to D3 here and working on the chart with the code below. I have a div called "tip" that shows up (by changing opacity) when user hovers over one of the textlabels. I am having trouble to position it right.

What I want is to position it in the upper left corner of the chart, let's say x,y coordinate of 10,10. But I don't know how to get that coordinate since it's a div. Anyone can help me?

var url = ".json";
d3.json(url, function(json) {

  var data = json;

  //Dimensions of the SVG container
  var margin = {
    top: 40,
    right: 100,
    bottom: 60,
    left: 60
  };
  //inner width for the chart, within SVG element
  var w = 1000 - margin.left - margin.right;
  //inner height for the chart, within SVG element
  var h = 800 - margin.top - margin.bottom;
  var padding = 20;

  //create SVG conratiner and append to DOM
  var svg = d3.select("#chart")
    .append("svg")
    .attr("width", w + margin.left + margin.right)
    .attr("height", h + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  var maxRank = d3.max(data, function(d) {

    return d.Place;

  });

  var minSeconds = d3.min(data, function(d) {

    return d.Seconds;

  });

  var maxSeconds = d3.max(data, function(d) {

    return d.Seconds;

  });

  var formatTime = d3.timeFormat("%M:%S");
  var formatSeconds = formatMinutes = function(d) {
    return formatTime(new Date(2016, 0, 0, 0, 1, d));
  };

  var xScale = d3.scaleLinear()
    .domain([maxSeconds + 5, minSeconds])
    .range([0, w]);

  var yScale = d3.scaleLinear()
    .domain([0, maxRank + 2])
    .range([0, h]);

  var xAxis = d3.axisBottom()
    .scale(xScale)
    .ticks(10)
    .tickFormat(formatMinutes)

  var yAxis = d3.axisLeft()
    .scale(yScale)
    .ticks(10);

  var tip = d3.select("#chart").append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);

  var circles = svg.selectAll("circle")
    .data(data)
    .enter()
    .append("circle");


  var circleAttributes = circles
    .attr("cx", function(d) {

      return xScale(d.Seconds);

    })
    .attr("cy", function(d) {

      return yScale(d.Place);

    })
    .attr("r", 6)
    .attr("class", "circles")
    .attr("fill", function(d) {

      if (d.Doping === "") {

        return "#2c3e50";

      } else {

        return "#e74c3c";

      }

    });

  var labels = svg.selectAll("text")
    .data(data)
    .enter()
    .append("text")
    .text(function(d) {

      return d.Name;

    })
    .attr("x", function(d) {

      return xScale(d.Seconds) + 7;

    })
    .attr("y", function(d) {

      return yScale(d.Place) + 4;

    })
    .attr("class", "labels")
    .attr("font-family", "roboto slab")
    .attr("font-size", "12px")
    .attr("fill", "#2c3e50")
    .on("mouseover", function(d) {

      tip.transition()
        .duration(200)
        .style("opacity", 0.7);
      tip.html("<span><strong>" + d.Name + "</strong><br/><i>Place: </i>" + d.Place + "<br/><i>Time: </i>" + d.Time + "<br/><i>Year: </i>" + d.Year + "<br/><i>Nationality: </i>" + d.Nationality + "<br/><i>Doping: </i>" + d.Doping + "</span>")
        .style("left", (d3.event.pageX + 48) + "px")
        .style("top", (d3.event.pageY + 48) + "px");

    })
    .on("mouseout", function(d) {

      tip.transition()
        .duration(200)
        .style("opacity", 0);

    });

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

  svg.append("g")
    .attr("class", "axis")
    .call(yAxis)

})

New to D3 here and working on the chart with the code below. I have a div called "tip" that shows up (by changing opacity) when user hovers over one of the textlabels. I am having trouble to position it right.

What I want is to position it in the upper left corner of the chart, let's say x,y coordinate of 10,10. But I don't know how to get that coordinate since it's a div. Anyone can help me?

var url = "https://raw.githubusercontent./FreeCodeCamp/ProjectReferenceData/master/cyclist-data.json";
d3.json(url, function(json) {

  var data = json;

  //Dimensions of the SVG container
  var margin = {
    top: 40,
    right: 100,
    bottom: 60,
    left: 60
  };
  //inner width for the chart, within SVG element
  var w = 1000 - margin.left - margin.right;
  //inner height for the chart, within SVG element
  var h = 800 - margin.top - margin.bottom;
  var padding = 20;

  //create SVG conratiner and append to DOM
  var svg = d3.select("#chart")
    .append("svg")
    .attr("width", w + margin.left + margin.right)
    .attr("height", h + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  var maxRank = d3.max(data, function(d) {

    return d.Place;

  });

  var minSeconds = d3.min(data, function(d) {

    return d.Seconds;

  });

  var maxSeconds = d3.max(data, function(d) {

    return d.Seconds;

  });

  var formatTime = d3.timeFormat("%M:%S");
  var formatSeconds = formatMinutes = function(d) {
    return formatTime(new Date(2016, 0, 0, 0, 1, d));
  };

  var xScale = d3.scaleLinear()
    .domain([maxSeconds + 5, minSeconds])
    .range([0, w]);

  var yScale = d3.scaleLinear()
    .domain([0, maxRank + 2])
    .range([0, h]);

  var xAxis = d3.axisBottom()
    .scale(xScale)
    .ticks(10)
    .tickFormat(formatMinutes)

  var yAxis = d3.axisLeft()
    .scale(yScale)
    .ticks(10);

  var tip = d3.select("#chart").append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);

  var circles = svg.selectAll("circle")
    .data(data)
    .enter()
    .append("circle");


  var circleAttributes = circles
    .attr("cx", function(d) {

      return xScale(d.Seconds);

    })
    .attr("cy", function(d) {

      return yScale(d.Place);

    })
    .attr("r", 6)
    .attr("class", "circles")
    .attr("fill", function(d) {

      if (d.Doping === "") {

        return "#2c3e50";

      } else {

        return "#e74c3c";

      }

    });

  var labels = svg.selectAll("text")
    .data(data)
    .enter()
    .append("text")
    .text(function(d) {

      return d.Name;

    })
    .attr("x", function(d) {

      return xScale(d.Seconds) + 7;

    })
    .attr("y", function(d) {

      return yScale(d.Place) + 4;

    })
    .attr("class", "labels")
    .attr("font-family", "roboto slab")
    .attr("font-size", "12px")
    .attr("fill", "#2c3e50")
    .on("mouseover", function(d) {

      tip.transition()
        .duration(200)
        .style("opacity", 0.7);
      tip.html("<span><strong>" + d.Name + "</strong><br/><i>Place: </i>" + d.Place + "<br/><i>Time: </i>" + d.Time + "<br/><i>Year: </i>" + d.Year + "<br/><i>Nationality: </i>" + d.Nationality + "<br/><i>Doping: </i>" + d.Doping + "</span>")
        .style("left", (d3.event.pageX + 48) + "px")
        .style("top", (d3.event.pageY + 48) + "px");

    })
    .on("mouseout", function(d) {

      tip.transition()
        .duration(200)
        .style("opacity", 0);

    });

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

  svg.append("g")
    .attr("class", "axis")
    .call(yAxis)

})
Share Improve this question edited Jan 23, 2017 at 11:30 Elfayer 4,57110 gold badges50 silver badges78 bronze badges asked Jan 23, 2017 at 10:15 chemook78chemook78 1,1983 gold badges18 silver badges39 bronze badges 1
  • Could you provide a working JSFiddle ? – Elfayer Commented Jan 23, 2017 at 10:22
Add a ment  | 

1 Answer 1

Reset to default 6

It seems to me that this problem has (almost) nothing to do with D3.js. Instead, it's a CSS problem.

There are some different solutions, the one I suggest here is very simple: just set the container div (the div with Id chart) a relative position...

#svgwrapper {
    position: relative;
}

... and, to the tooltip div, an absolute position, with zero for top and left:

.tooltip {
    position: absolute;
    top: 0 px;
    left: 0 px;
}

Also, don't forget to drop those d3.event.pageX and d3.event.pageY, since your tooltip will always show up at the same position.

Here is a demo (hover over the circle):

var tip = d3.select("#svgwrapper").append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);
		
d3.select("circle").on("mouseover", function(){
    tip.html("Hello!")
		.style("opacity", 1)
}).on("mouseout", function(){
    tip.style("opacity", 0)
});
#svgwrapper {
	border: 1px solid gray;
	position: relative;
}

.tooltip {
	position: absolute;
	top: 0px;
	left: 0px;
	border: 1px solid gray;
	border-radius: 2px;
	padding: 4px;
	background-color: tan;
}
<script src="https://cdnjs.cloudflare./ajax/libs/d3/3.4.11/d3.min.js"></script>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea modo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</div>
<div id="svgwrapper">
<svg>
	<circle cx="100" cy="100" r="20" fill="teal"></circle>
</svg>
</div>

本文标签: javascriptPosition a div in upper left corner of a chart in D3 JSStack Overflow