1

I would like to achieve jQuery Knob-like effect using HTML5 Canvas, but with a circle knob/cursor, instead of the stroke cursor effect that jQuery Knob does.

Based on jQuery Knob code, I was managed to connect the onMouseMove event with my circle knob/cursor so the circle knob moves according to the X and Y coordinates of where the mouse is. However I cannot "restrict" the knob to move only on/along the circle path just like this example, so if I click/mousedown inside the circle path, the circle knob moves to inside the path.

Is there any way to achieve this only using Canavas and jQuery, not Raphael like the example above?

One of my thoughts was to move the circle knob back on track (on the path) whenever mousemove event occurs outside the path (like this). However no luck in succeeding the calculation for this. Is there any math/geometry formula I can use to achieve this?

alex
  • 479,566
  • 201
  • 878
  • 984
shibalink
  • 139
  • 2
  • 3
  • 9

1 Answers1

5

Just a little bit of trigonometry will answer your question!

This code will find the point on a circle closest to a mouseclick.

var rads = Math.atan2(mouseY - knobCenterY, mouseX - knobCenterX);
var indicatorX=knobRadius*Math.cos(rads)+knobCenterX;
var indicatorY=knobRadius*Math.sin(rads)+knobCenterY;

This code will put an indicator on the knob closest to where the user clicks

And here is a Fiddle --- http://jsfiddle.net/m1erickson/pL5jP/

    <!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>
    <!--[if lt IE 9]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->

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

    <script>
    $(function(){

        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        var canvasOffset=$("#canvas").offset();
        var offsetX=canvasOffset.left;
        var offsetY=canvasOffset.top;
        var circleArc=Math.PI*2;

        // drawing design properties
        var knobCenterX=100;
        var knobCenterY=100;
        var knobRadius=50;
        var knobColor="green";
        var indicatorRadius=5;
        var indicatorColor="yellow";

        Draw(canvas.width/2,1); // just to get started

        function Draw(mouseX,mouseY){
            // given mousePosition, what is the nearest point on the knob
            var rads = Math.atan2(mouseY - knobCenterY, mouseX - knobCenterX);
            var indicatorX=knobRadius*Math.cos(rads)+knobCenterX;
            var indicatorY=knobRadius*Math.sin(rads)+knobCenterY;
            // start drawing
            ctx.clearRect(0,0,canvas.width,canvas.height);
            // draw knob
            ctx.beginPath();
            ctx.arc(knobCenterX,knobCenterY,knobRadius,0,circleArc,false);
            ctx.fillStyle="ivory";
            ctx.fill();
            ctx.lineWidth=2;
            ctx.strokeStyle=knobColor;
            ctx.stroke();
            // draw indicator
            ctx.beginPath();
            ctx.arc(indicatorX, indicatorY, indicatorRadius, 0, circleArc, false);
            ctx.fillStyle = indicatorColor;
            ctx.fill();
            ctx.lineWidth = 2;
            ctx.strokeStyle = 'black';
            ctx.stroke();
        }

        function handleMouseDown(e){
          MouseX=parseInt(e.clientX-offsetX);
          MouseY=parseInt(e.clientY-offsetY);
          Draw(MouseX,MouseY);
        }

        $("#canvas").mousedown(function(e){handleMouseDown(e);});

    }); // end $(function(){});
    </script>

    </head>

    <body>

        <br/><p>Click anywhere in the canvas to set the knob indicator</p><br/>
        <canvas id="canvas" width=200 height=200></canvas>

    </body>
    </html>
markE
  • 102,905
  • 11
  • 164
  • 176
  • Thanks so much for your answer markE! It worked perfectly and exactly the way I wanted. – shibalink Feb 24 '13 at 18:09
  • I actually have a follow-up question: I would also like to relate this indicator to the value shown in the center of the circle in jQuery Knob. I've found the angle function (this.angle(v)) that moves its default cursor to the right angle according to the value/value change, so I went on doing something like : A = this.angle(value); if(value changed){rads = A}, but seems to be the calculation for the A isn't right. Could you tell me how I can get the right angle based on the value? Thanks a bunch in advance! – shibalink Feb 24 '13 at 23:01
  • So a circle is 2 * Math.PI radians = 2 * 3.14159 = 6.283185 radians. Therefore, you can tell what percent of the circle you have navigated like this: #radiansCompleted / 6.28315 * 100. For example, if you have navigated 2 radians of the circle, you are 2 / 6.28315 *100 = 31.83 percent around the circle. – markE Feb 25 '13 at 00:21