draw polygon shape on canvas and allow tooltip on

2019-08-31 03:18发布

问题:

This is basically my requirement and not an issue, i have to draw polygon shape on canvas(same as paint) which i have achieved however i am stuck with my requirement where i have to display tool tip on hovering over each polygon drawn. I know for shapes like rectangle it would be easier where i can manage coordinates using simple for loops ,but how to handle it for polygon. Is it even possible? Below is my code for drawing polygon

    var startPointX = "", startPointY = "", endpointX, endpointY, isnewShape = false;
tools.polygon = function () {
    var tool = this;
    this.started = false;

    this.mousedown = function (ev) {
        tool.started = true;
        tool.x0 = ev._x;
        tool.y0 = ev._y;

        if ((Math.abs(startPointX - ev._x) < 5) && (Math.abs(startPointY - ev._y) < 5) && (startPointX != ev._x && startPointY != ev._y) && !isnewShape) {
            alert('point matched');
            startPointX = "";
            startPointY = "";
            isnewShape = true;
            context.clearRect(0, 0, canvas.width, canvas.height);

            context.beginPath();
            context.moveTo(endpointX, endpointY);

            context.lineTo(ev._x, ev._y);
            endpointX = ev._x;
            endpointY = ev._y;
            context.stroke();
            context.closePath();
            img_update();
            tool.started = false;
        }
        else {
            //                console.log(isnewShape);

            if (startPointX == "" || startPointY == "")
                return;

            context.clearRect(0, 0, canvas.width, canvas.height);

            context.beginPath();
            context.moveTo(endpointX, endpointY);
            isnewShape = false;
            context.lineTo(ev._x, ev._y);
            endpointX = ev._x;
            endpointY = ev._y;
            context.stroke();
            context.closePath();
            img_update();
        }

    };

    this.mousemove = function (ev) {
        if (!tool.started) {
            return;
        }
        // console.log('mousemove');
        context.clearRect(0, 0, canvas.width, canvas.height);

        context.beginPath();
        context.lineTo(ev._x, ev._y);
        endpointX = ev._x;
        endpointY = ev._y;
        context.stroke();
        context.closePath();
    };

    this.mouseup = function (ev) {
        if (tool.started) {

            if (startPointX == "" && startPointY == "") {

                startPointX = tool.x0;
                startPointY = tool.y0;

           }

            tool.started = false;
            img_update();
        }
    };
};

回答1:

As well as maintaining the canvas that the user sees, draw everything on a second canvas that is hidden. The important thing is that each polygon should be in its own colour. It doesn't have to be human-distinguishable - you could draw the first as #000000, the second #000001, and so on. This provides support for 16 million polygons - should be enough!

Then, when the user moves the mouse over the canvas, find out the position of the mouse and look at what colour is there on your hidden canvas. This will tell you which shape is being hovered over, and you can act accordingly.



回答2:

You can use canvas's built in hit-testing method: context.isPointInPath(x,y);

isPointInPath will test if x,y is inside the most recently defined path.

It works like this:

Presumably you have the coordinates that define each polygon

// create an object holding all polygon points

var triangle=[{x:100,y:50},{x:150,y:100},{x:50,y:100}];

To do the hit-test, first redefine the triangle:

// define the polygon

function define(polygon){
    ctx.beginPath();
    ctx.moveTo(polygon[0].x,polygon[0].y);
    for(var i=1;i<polygon.length;i++){
        ctx.lineTo(polygon[i].x,polygon[i].y);
    }
    ctx.closePath();
}

Then use isPointInPath to check whether any x,y is inside that redefined triangle

console.log( ctx.isPointInPath(mouseX,mouseY); );

Here's example code and a Demo: http://jsfiddle.net/m1erickson/d3kdf/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    #canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();

    var $results=$("#results");

    // create an object holding all polygon points
    var triangle=[{x:100,y:50},{x:150,y:100},{x:50,y:100}];

    // draw the polygon
    define(triangle);
    ctx.fill();

    // define the polygon
    function define(polygon){
        ctx.beginPath();
        ctx.moveTo(polygon[0].x,polygon[0].y);
        for(var i=1;i<polygon.length;i++){
            ctx.lineTo(polygon[i].x,polygon[i].y);
        }
        ctx.closePath();
    }


    function hitTest(polygon){
        // redefine the polygon
        // (necessary to isPointInPath to work
        define(polygon);
        // ask isPointInPath to hit test the mouse position
        // against the current path
        return(ctx.isPointInPath(mouseX,mouseY));
    }

    function handleMouseMove(e){
      e.preventDefault();
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // check if the mouse is inside the polygon
      var isInside=hitTest(triangle);
      if(isInside){
          $results.text("Mouse is inside the Triangle");
      }else{
          $results.text("Outside");
      }

    }

    $("#canvas").mousemove(function(e){handleMouseMove(e);});

}); // end $(function(){});
</script>
</head>
<body>
    <p id="results">Hit results</p>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>