1

[Update]

Click jsfiddle here.


[Original Post]

How can I limit the coordinates of cross hair when moving the mouse? Notice when I move my mouse to the left of x-axis or bottom of y-axis, the cross hair and text still shows. I want the cross hair and text to stop showing when either mouse is moved to the left of x-axis or bottom of y-axis.

I have tried to add if else to limit the cross hair, but it didn't work. For instance, I tried something like .style("display", (xCoord>=minX & xCoord<=maxX & yCoord>=minY & yCoord<=maxY) ? "block" : "none") in the addCrossHair() function.

<!DOCTYPE html>
<meta charset="utf-8">
<head>
    <style>
        .axis path,
        .axis line
        {
            fill:none;
            rendering:crispEdges;
            stroke:black;
            width:2.5;
        }
    </style>
</head>
<body>
    <script src="d3.min.js"></script>
    <script>
        var width = 800,
            height = 600;

        var randomX = [],
            randomY = [];
        for (var i = 0; i <= 500; i++) {
            randomX[i] = Math.random() * 400;
            randomY[i] = Math.random() * 400;
        }

        var minX = d3.min(randomX),
            maxX = d3.max(randomX),
            minY = d3.min(randomY),
            maxY = d3.max(randomY);

        var xScale = d3.scale.linear().domain([minX, maxX]).range([0, width]);
        var xAxis = d3.svg.axis().scale(xScale).orient("bottom");
        var yScale = d3.scale.linear().domain([minY, maxY]).range([height, 0]);
        var yAxis = d3.svg.axis().scale(yScale).orient("left");

        var svgContainer = d3.select("body").append("div").append("svg").attr("width", width).attr("height", height);
        var svg = svgContainer.append("g").attr("transform", "translate(50, 50)");

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

        var crossHair = svg.append("g").attr("class", "crosshair");
        crossHair.append("line").attr("id", "h_crosshair") // horizontal cross hair
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", 0)
            .style("stroke", "gray")
            .style("stroke-width", "1px")
            .style("stroke-dasharray", "5,5")
            .style("display", "none");

        crossHair.append("line").attr("id", "v_crosshair") // vertical cross hair
            .attr("x1", 0)
            .attr("y1", 0)
            .attr("x2", 0)
            .attr("y2", 0)
            .style("stroke", "gray")
            .style("stroke-width", "1px")
            .style("stroke-dasharray", "5,5")
            .style("display", "none");

        crossHair.append("text").attr("id", "crosshair_text") // text label for cross hair
            .style("font-size", "10px")
            .style("stroke", "gray")
            .style("stroke-width", "0.5px");

        svgContainer.on("mousemove", function () {
            var xCoord = d3.mouse(this)[0] - 50,
                yCoord = d3.mouse(this)[1] - 50;
                addCrossHair(xCoord, yCoord);
            })
            .on("mouseover", function () {d3.selectAll(".crosshair").style("display", "block");})
            .on("mouseout", function () {d3.selectAll(".crosshair").style("display", "none");});

        function addCrossHair(xCoord, yCoord) {
            // Update horizontal cross hair
            d3.select("#h_crosshair")
                .attr("x1", xScale(minX))
                .attr("y1", yCoord)
                .attr("x2", xScale(maxX))
                .attr("y2", yCoord)
                .style("display", "block");
            // Update vertical cross hair
            d3.select("#v_crosshair")
                .attr("x1", xCoord)
                .attr("y1", yScale(minY))
                .attr("x2", xCoord)
                .attr("y2", yScale(maxY))
                .style("display", "block");
            // Update text label
            d3.select("#crosshair_text")
                .attr("transform", "translate(" + (xCoord + 5) + "," + (yCoord - 5) + ")")
                .text("(" + xScale.invert(xCoord) + " , " + yScale.invert(yCoord) + ")");
        }

        svg.selectAll("scatter-dots")
            .data(randomY)
            .enter().append("svg:circle")
            .attr("cy", function (d) {
                return yScale(d);
            })
            .attr("cx", function (d, i) {
                return xScale(randomX[i]);
            })
            .style("fill", "brown")
            .attr("r", 3)
    </script>
</body>
Boxuan
  • 4,937
  • 6
  • 37
  • 73
  • Can you provide a [jsfiddle](http://jsfiddle.net)? – Dom Jun 12 '14 at 16:52
  • @Dom Here you go, http://jsfiddle.net/BWW66/ – Boxuan Jun 12 '14 at 17:00
  • You would usually make the plot region a translated `g` within the overall SVG. You'll notice that your dots overlap/go outside the axes as well. By restricting the plot region to be to the right and above of the axes, you'll fix both these problems. – Lars Kotthoff Jun 12 '14 at 17:07
  • @LarsKotthoff Notice I have `var svgContainer` for the actual `` and `var svg` for the translated ``. When I tried to append `` to my `var svg`, the crosshair will only show when I mouse over a point, but not general mouse movement. – Boxuan Jun 12 '14 at 17:13
  • The points and the axes are in the same `g` (`svg`). My approach would be to put them in separate `g`s that are translated with respect to each other. – Lars Kotthoff Jun 12 '14 at 17:20
  • @LarsKotthoff I have cleaned up my jsfiddle, but I still can't get it to work. Could you modify it according to your suggestion? – Boxuan Jun 12 '14 at 17:38

1 Answers1

3

The way to do this is to make the actual canvas (i.e. where you're drawing the dots) a separate g element from the ones that the axes are rendered into. Then the canvas can be translated such that it sits to the right and above the axes. The crosshair handler would be attached to this canvas g element (which is not quite straightforward, see this question) and the crosshairs or dots won't appear outside of the canvas.

Complete demo here.

Community
  • 1
  • 1
Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204