Search code examples
javascriptasp.netc#-4.0html5-canvasajaxcontroltoolkit

AjaxToolKit: Balloon Popup Extender on html5 Canvas


I have a canvas drawing implemented on my project. I would like to show speech-bubbles with information related to specific mouse clicks on the canvas. Say a click on a particular region of my canvas allows for a popup that gives text information about that region on the canvas.

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.min.js"></script>


<ajaxToolkit:BalloonPopupExtender ID="BalloonPopupExtender1" 
    runat="server"  
    TargetControlID="myCanvas" 
    BalloonPopupControlID="Panel1"
    Position="TopLeft" 
    BalloonStyle="Cloud"
    BalloonSize="Small"
    CustomCssUrl="CustomStyle/BalloonPopupOvalStyle.css"
    CustomClassName="oval"
    UseShadow="true" 
    ScrollBars="Auto"
    DisplayOnMouseOver="true"
    DisplayOnFocus="false"
    DisplayOnClick="true" />

<canvas id="myCanvas" width="915" height="850" style="border: 2px double #000000;"></canvas>
<script type="text/javascript">

However this doesn't work, I believe this is because myCanvas is not a asp.net/server side element, hence runat ="server" isn't correct methodology.

I am currently following these blogs:-

http://www.c-sharpcorner.com/UploadFile/364074/balloonpopupextendercontrol-in-ajax/

http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/BalloonPopup/BalloonPopupExtender.aspx

Any idea how to implement the popup on the canvas, upon a click?


Solution

  • Given that you want to respond to clicks on specific canvas coordinates, you might have to work on the client side. Here's code to do an info popup on the client side.

    enter image description here

    This is code that will draw an info balloon inside a separate canvas element. The canvas is moved off-screen until it's needed. You can of course, style this popup balloon in any way you want because it's a canvas element!

    <canvas id="balloon" width=105 height=105></canvas>
    
    function drawBalloon(X,Y,theInfo){
        popCtx.save();
        popCtx.fillStyle="#FD0";
        popCtx.strokeStyle="#000";
        // draw the balloon
        popCtx.beginPath();
        popCtx.moveTo(52,02);
        popCtx.quadraticCurveTo(02,02,02,42);
        popCtx.quadraticCurveTo(02,77,27,77);
        popCtx.quadraticCurveTo(27,102,07,102);
        popCtx.quadraticCurveTo(37,102,42,77);
        popCtx.quadraticCurveTo(102,77,102,42);
        popCtx.quadraticCurveTo(102,02,52,02);
        popCtx.lineWidth=3;
        popCtx.stroke();
        popCtx.fill();
        // draw theInfo
        popCtx.font="10pt arial";
        popCtx.fillStyle="black";
        popCtx.fillText(theInfo,10,50);
        popCtx.restore();
        // move the balloon canvas to the target
        $("#balloon").css({left:offsetX+X, top:offsetY+Y});
    } 
    

    If you're not used to client-side javascript, here's how to get the position of the target-filled canvas relative to the window

    <canvas id="canvas" width=300 height=300></canvas>
    
    // get the position of canvas relative to window
    var canvasOffset=$("#canvas").offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    

    And here's how to listen for clicks on the target-filled canvas.

    // listen for clicks on the canvas
    $("#canvas").click(function(e){ 
    
        // get the mouseclick position
        mouseX=parseInt(e.clientX-offsetX);
        mouseY=parseInt(e.clientY-offsetY);
    
        // see if we clicked on any targets, show the balloon
        for(var i=0;i<circles.length;i++){
            var circle=circles[i];
            var dx=circle.x-mouseX;
            var dy=circle.x-mouseY;
            var radius=circle.radius;
            // true if we clicked in the target circle
            if(dx*dx+dy*dy<=radius*radius){
                drawBalloon(circles[i].x+radius,circles[i].y-100,circles[i].info);
            }
        }
    });
    

    To test if any target location on the canvas was clicked, we can test a circular area around the target like this:

        var dx=targetCircle.x-mouseX;
        var dy=targetCircle.x-mouseY;
        var radius=targetCircle.radius;
        // true if we clicked in the target circle
        if(dx*dx+dy*dy<=radius*radius){
            // we hit a target, display the balloon
        }
    

    Here is working example code and a Fiddle: http://jsfiddle.net/m1erickson/AJvkN/

    <!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; padding:10px;padding-top:100px; }
        #canvas{border:1px solid red;}
        #balloon{ position:absolute; left:-200px; }
    </style>
    
    <script>
    $(function(){
    
        // get reference to our drawing canvas
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        // get reference to our balloon canvas
        var balloon=document.getElementById("balloon");
        var popCtx=balloon.getContext("2d");
    
        // get the position of canvas relative to window
        var canvasOffset=$("#canvas").offset();
        var offsetX=canvasOffset.left;
        var offsetY=canvasOffset.top;
    
        // define some targets and their basic info
        var circles=[];
        circles.push({x:40,  y:30, radius:15,color:"red",  info:"I'm red."});
        circles.push({x:150, y:150,radius:25,color:"green",info:"I'm centered."});
        circles.push({x:110, y:85, radius:40,color:"blue", info:"I'm big."});
    
        // draw the target circles on the canvas
        for(var i=0;i<circles.length;i++){
            drawCircle(circles[i]);
        }
    
        // listen for clicks on the canvas and show the balloon
        $("#canvas").click(function(e){ 
    
            // get the mouseclick position
            mouseX=parseInt(e.clientX-offsetX);
            mouseY=parseInt(e.clientY-offsetY);
    
            // see if we clicked on any targets
            for(var i=0;i<circles.length;i++){
                var circle=circles[i];
                var dx=circle.x-mouseX;
                var dy=circle.x-mouseY;
                var radius=circle.radius;
                // true if we clicked in the target circle
                if(dx*dx+dy*dy<=radius*radius){
                    drawBalloon(circles[i].x+radius,circles[i].y-100,circles[i].info);
                }
            }
        });
    
    
        // listen for clicks on the balloon and then hide the balloon
        $("#balloon").click(function hideBalloon(e){ $("#balloon").css({left:-200}); });
    
    
        function drawCircle(circle){
            ctx.save();
            ctx.beginPath();
            ctx.fillStyle=circle.color;
            ctx.strokeStyle="black";
            ctx.lineWidth=3;
            ctx.arc(circle.x,circle.y,circle.radius,0,Math.PI*2,false);
            ctx.closePath();
            ctx.fill();
            ctx.stroke();
            ctx.restore();
        }
    
    
        function drawBalloon(X,Y,theInfo){
            popCtx.save();
            popCtx.fillStyle="#FD0";
            popCtx.strokeStyle="#000";
            // draw the balloon
            popCtx.beginPath();
            popCtx.moveTo(52,02);
            popCtx.quadraticCurveTo(02,02,02,42);
            popCtx.quadraticCurveTo(02,77,27,77);
            popCtx.quadraticCurveTo(27,102,07,102);
            popCtx.quadraticCurveTo(37,102,42,77);
            popCtx.quadraticCurveTo(102,77,102,42);
            popCtx.quadraticCurveTo(102,02,52,02);
            popCtx.lineWidth=3;
            popCtx.stroke();
            popCtx.fill();
            // draw theInfo
            popCtx.font="10pt arial";
            popCtx.fillStyle="black";
            popCtx.fillText(theInfo,10,50);
            popCtx.restore();
            // move the balloon canvas to the target
            $("#balloon").css({left:offsetX+X, top:offsetY+Y});
        }
    
    }); // end $(function(){});
    </script>
    
    </head>
    
    <body>
        <p>Click circles to popup an info balloon</p>
        <p>When info balloon appears, click it do dismiss it</p>
        <canvas id="canvas" width=300 height=300></canvas>
        <canvas id="balloon" width=105 height=105></canvas>
    </body>
    </html>