skip to Main Content

I’m trying to create a sunflower effect on canvas, with an arc, and my geometry skills are rusty.

To start, I created an origin point somewhere in the middle of the canvas, Origin (X1, Y1)
Then I create get the Mouse Position Mp (Xm, Ym)

Now if I make an imaginary line from Origin to Mp, then Mp should be the point that bisects the arc with a new smaller origin point which is in the direction of the Origin, that will define the arc with a static radius (say 20). All three points Origin, Mp and the smaller Radius should form a straight line.

I want it to cut through the centre of the arc with a static radius (say 20) regardless of how close of far the mouse is from Origin.

So, if you imagine a clock. If the middle part where the hands connect is Origin.

  • If the mouse is at the 3 o’clock position the Arc looks like a “)”
  • If the mouse is at the 9 o’clock position the Arc looks like a “(”
  • If the mouse is at the 12 o’clock position the Arc looks like a “(” if it were rotated 90°
  • If the mouse is at the 6 o’clock position the Arc looks like a “(” if it were rotated 270°
  • etc…

And the mouse is on top of that Arc.

For my question, specifically it’s not so much the how to get points, or mouseevents or anything, but assuming I have {X1,Y1} and {Xm,Ym}, what is the math needed to make an arc as described above?

Or for the JS/jQuery experts, the arc() params?

Edit: a very poor photoshop render
Curves

The bottom right one has a mouse added to show generally where the mouse pointer is at the time the arc/curve is drawn.

2

Answers


  1. Chosen as BEST ANSWER

    Adding Just because:

    $(document).ready(function() {
          var canvas = $('#canvas');
    
          function getPosition(mouseEvent) {
            var x, y;
            x = mouseEvent.clientX;
            y = mouseEvent.clientY;
            return {
              X: x - canvas.offset().left,
              Y: y - canvas.offset().top
            };
          }
    
          $('#canvas').mousemove(function(e) {
            var origin = {
              x: 325,
              y: 100
            };
            var posit = getPosition(e)
            var degrees = Math.PI /
              180;
            var plotR = {
              X: 0,
              Y: 0
            };
            var radius = 15;
            var curveDeg = 65;
            var context = $('#canvas').get(0).getContext('2d');
    
            if (posit.X >= origin.x && posit.Y <= origin.y) {
              quadrant = 1;
            } else if (posit.X >= origin.x && posit.Y >= origin.y) {
              quadrant = 2;
            } else if (posit.X < origin.x && posit.Y >= origin.y) {
              quadrant = 3;
            } else {
              quadrant = 4;
            }
    
            deltaY = posit.Y - origin.y;
            deltaX = posit.X - origin.x;
    
            if (deltaX == 0) {
              distance = deltaY;
              plotR.X = origin.x;
              switch (quadrant) {
                case 2:
                case 3:
                  plotR.Y = posit.Y - radius;
                  break;
                case 1:
                case 4:
                default:
                  plotR.Y = posit.Y + radius;
                  break;
              }
            } else {
              distance = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
              slope = deltaY / deltaX;
              delta = radius / (Math.sqrt(1 + Math.pow(slope, 2)));
    
              switch (quadrant) {
                case 1:
                  plotR.Y = posit.Y - slope * delta;
                  plotR.X = posit.X - delta;
                  break;
                case 2:
                  plotR.Y = posit.Y - slope * delta;
                  plotR.X = posit.X - delta;
                  break;
                case 3:
                  plotR.Y = posit.Y + slope * delta;
                  plotR.X = posit.X + delta;
    
                  break;
                case 4:
                default:
                  plotR.Y = posit.Y + slope * delta;
                  plotR.X = posit.X + delta;
                  break;
              }
            }
            startAngle = Math.acos(deltaX / distance);
            if (quadrant == 1 || quadrant == 4) startAngle = -startAngle;
    
    
            context.clearRect(0, 0, 900, 400);
    
            // Draw Origin Point for reference, but not for production
            context.beginPath();
            context.lineWidth = 1;
            context.fillStyle = "#0000FF";
            context.strokeStyle = "#0000FF";
            context.arc(origin.x, origin.y, 3, 0, 2 * Math.PI, true);
            context.fill();
    
            // Drawn Calculated Origin point offset from Mouse in the direction of Origin Point
            context.beginPath();
            context.lineWidth = 1;
            context.fillStyle = "#00FF00";
            context.strokeStyle = "#00FF00";
            context.arc(plotR.X, plotR.Y, 3, 0, 2 * Math.PI, true);
            context.fill();
    
            // Draw 'Sunflower' Curve
            context.beginPath();
            context.lineCap = 'round';
            context.lineWidth = 3;
            context.strokeStyle = "#FF0000";
            context.arc(plotR.X, plotR.Y, radius, startAngle - (curveDeg * degrees / 2), startAngle + (curveDeg * degrees / 2), false);
    
            context.stroke();
            return;
          });
        });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <canvas id="canvas" width="650" height="200" style=" border: 1px #000 solid"></canvas>


  2. The simplest way is to adjust the starting & ending angles of the arc command.

    You can draw a series of arc’s to form your flower.

    Hint: If you want your petals to be less round and more curved, you might use quadraticCurveTo instead of arcs to draw the outside of the petals.

    Good luck with your project!

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw=canvas.width;
    var ch=canvas.height;
    
    var cx=150;
    var cy=150;
    var radius=50;
    var PI=Math.PI;
    var startAngle=0-PI/8;
    var sweepAngle=PI/4;
    var nextTime=0;
    var delay=250;
    
    requestAnimationFrame(animate);
    
    function draw(){
    
      ctx.clearRect(0,0,cw,ch);
    
      ctx.beginPath();
      ctx.arc(cx,cy,5,0,PI*2);
      ctx.closePath();
      ctx.fill();
    
      ctx.beginPath();
      ctx.arc(cx,cy,radius,startAngle,startAngle+sweepAngle);
      ctx.stroke();
    
    }
    
    function animate(time){
      requestAnimationFrame(animate);
      if(time>nextTime){
        draw();
        startAngle+=PI*2/30;
        nextTime+=delay;
      }
    }
    body{ background-color: ivory; padding:10px; }
    #canvas{border:1px solid red;}
    <canvas id="canvas" width=300 height=300></canvas>

    [ Addition based on more information ]

    Yep, I think you’ve got it!

    Start with the mouse position mcx,mcy.

    Define an angle that a smaller circle centerpoint is versus the mouse position radianAngle.

    Define how far that small centerpoint is away from the mouse centerpoint radius.

    Calculate the centerpoint of the small circle:

    var scx = mcx + radius*Math.cos(radianAngle);
    var scy = mcy + radius*Math.sin(radianAngle);
    

    Define the radius of the smaller circle smallRadius.

    Define the total sweepAngle you want on the smaller arc sweepAngle.

    Define the starting & ending angles of the arc on your small circle. This is actually easy because you want the small arc to “point” at the mouse point. Hint: The center of the small arc must always be the at the midpoint of the radianAngle. Therefore, the startingAngle = ( radianAngle - sweepAngle/2.

    So finally your small angle that “points” to the mouse becomes:

    ctx.arc( scx,scy, smallRadius, startingAngle, startingAngle+sweepAngle );
    

    Cheers!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search