开发者

Rotate 'note' on the canvas to always touch the upper left corner

The final code that worked for me was:

    <canvas id="bg-admin-canvas" width="500" height="500" style="margin:15px; background:#09F;"></canvas>
    <script>
        var postit = function(width,height,angle){
            var canvas = document.getElementById("bg-admin-canvas");
            var ctx = canvas.getContext("2d");

            var radians = angle * Math.PI / 180;                
            var move = width*Math.sin(radians);
            if(angle < 0 ){ ctx.translate(0,-move); }else{ ctx.translate(move,0); }
            ctx.rotate(radians);

            var gradient = ctx.createLinearGradient(0,height,width/2,height/2);
            gradient.addColorStop(0.05,"rgba(0,0,0,0)");
            gradient.addColorStop(0.5,"rgba(0,0,0,0.3)");
            ctx.fillStyle = gradient;
            ctx.fillRect(0,0,width,height);

            ctx.beginPath();
            ctx.moveTo(0,0);
            ctx.lineTo(width, 0);
            ctx.lineTo(width,height);
            ctx.lineTo(width-width*.8,height-height*.02);
            ctx.quadraticCurveTo(0+width*.02,height-height*.02,0+width*.02,(height - height*.2));
            ctx.closePath();
            var gradient = ctx.createLinearGradient(0,height,width/2,height/2);
            gradient.addColorStop(0,'#f7f8b9');
            gradient.addColorStop(1,'#feffcf');
            ctx.fillStyle = gradient;
            ctx.fill();

            ctx.beginPath();
            ctx.moveTo(width-width*.8,height-height*.02);
            ctx.quadraticCurveTo(0+width*.02,height-height*.02,0+width*.02,(height - height*.2));
            ctx.quadraticCurveTo(width*.05,height-height*.05,width*.1,height-height*.1);
            ctx.quadraticCurveTo(width*.1,height-height*.07,width-width*.8,height-height*.02);
            ctx.closePath();
            ctx.fillStyle = '#ffffff';
            ctx.fill();
            var gradient = ctx.createLinearGradient(0,height,width*.1,height-height*.1);
            gradient.addColorStop(0,"rgba(222,222,163,0.8)");
            gradient.addColorStop(1,'#feffcf');
            ctx.fillStyle = gradient;
            ctx.fill();

        }
        postit(300, 300, 10);
    </script>

Hi,

I made a quick and dirty "post-it" note with html5's canvas and some js.

I want to be able to rotate them anyway I want so I tried to use the translate. The example below I have a translate of 0,250 just so you could see the whole thing.

Ideally, I know if my canvas was 300,300 then I would ctx.translate(150,150); ctx.rotate(-30); ctx.translate(-150,-150);

Of course since I'm rotating a square it gets cut off.

How would I rotate the square and move it on the canvas so the whole thing is showing but at the very top left edge of the canvas?

I added an image with my thinking of just getting the height of a triangle and moving it that much, but when translated, it doesn't seem to work just right.

I'll paste my whole function so you can look at it, but if you have any ideas, I would appreciate it. This isn't important, just messing around today.

var postit = function(width,height,angle){
            var canvas = jQuery("#bg-admin-canvas").get(0);
            var ctx = canvas.getContext("2d");

            /*var area = (width*width*Math.sin(angle))/2;
            var h = (area*2) / width + 30;
            ctx.translate(0,h);
            */
            //ctx.translate(150,150);
            ctx.translate(0,250);
            ctx.rotate(angle*Math.PI / 180);
            //ctx.translate(-150,-150);

            var gradient = ctx.createLinearGradient(0,height,width/2,height/2);
            gradient.addColorStop(0.05,"rgba(0,0,0,0)");
            gradient.addColorStop(0.5,"rgba(0,0,0,0.3)");
            ctx.fillStyle = gradient;
            ctx.fillRect(0,0,width,height);

            ctx.beginPath();
            ctx.moveTo(0,0);
            ctx.lineTo(width, 0);
            ctx.lineTo(width,height);
            ctx.lineTo(width-width*.8,height-height*.02);
            ctx.quadraticCurveTo(0+width*.02,height-height*.02,0+width*.02,(height - height*.2));
            ctx.closePath();
            var gradient = ctx.createLinearGradient(0,height,width/2,height/2);
            gradient.addColorStop(0,'#f7f8b9');
            gradient.addColorStop(1,'#feffcf');
            ctx.fillStyle = gradient;
            ctx.fill();

            ctx.beginPath();
            ctx.moveTo(width-width*.8,height-height*.02);
            ctx.quadraticCurveTo(0+width*.02,height-height*.02,0+width*.02,(height - height*.2));
            ctx.quadraticCurveTo(width*.05,height-height*.05,width*.1,height-height*.1);
            ctx.quadraticCurveTo(width*.1,height-height*.07,width-width*.8,height-height*.02);
            ctx.closePath();
            ctx.fillStyle = '#ffffff';
            ctx.fill();
            var gradient = ctx.createLinearGradient(0,height,width*.1,height-height*.1);
            gradient.addColorStop(0,"rgba(222,222,163,0.8)");
            gradient.addColorStop(1,'#feffcf');
            ctx.fillStyle = gradient;
            ctx.fill();
        }
        postit(300, 300, -35);

Rotate 'note' on the canvas to always touch the upper left corner


MORE INFO

Phrog, I think you know what I'm trying to do. This image shows what I want to do:

Rotate 'note' on the canvas to always touch the upper left corner

Now, the only thing is, I want to be able to pass in any width and height and angle and make the adjustment on the fly.

As an example with the following code:

var canvas = document.getElementById("bg-admin-canvas");
var ctx = canvas.getContext("2d");
ctx.arc(0,0,3,0,360,true); ctx.fill();
ctx.translate(50, 50);
ctx.arc(0,0,3,0,360,true); ctx.fill();
ctx.translate(-25, -25);
ctx.arc(0,0,3,0,360,true); ctx.fill();

I get the following image:

Rotate 'note' on the canvas to always touch the upper left corner

Now, if I add a rotate in there like this:

var canvas = document.getElementById("bg-admin-canvas");
var ctx = canvas.getContext("2d");
ctx.arc(0,0,3,0,360,true); ctx.fill();
ctx.translate(50, 50);
ctx.arc(0,0,3,0,360,true); ctx.fill();
ctx.rotate(30*Math.PI/180);
ctx.transl开发者_如何学JAVAate(-25, -25);
ctx.arc(0,0,3,0,360,true); ctx.fill();

I now have a sloped coordinates as the result is:

Rotate 'note' on the canvas to always touch the upper left corner

As I found, this is because the coordinates are no longer horizontal and vertical.

So, with this rotated coordinate structure, I can't figure out how to move my square (which could be any size and rotated at any angle) back to the left and top (so it fits in as little space as possible)

Does that make sense?


In short:

  • Translate the context in the Y direction only to put the corner where it should be.
  • Rotate the context around this offset point.
  • Draw your object at 0,0.

Here is an interactive, working example, which you can see online here:
http://phrogz.net/tmp/canvas_rotate_square_in_corner.html

<!DOCTYPE HTML> 
<html lang="en"><head> 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
  <title>HTML5 Canvas Rotate Square in Corner</title> 
  <style type="text/css" media="screen"> 
    body { background:#eee; margin:2em; text-align:center }
    canvas { display:block; margin:auto; background:#fff; border:1px solid #ccc }
  </style> 
</head><body> 
<canvas width="250" height="200"></canvas>
<script type="text/javascript" charset="utf-8"> 
  var can = document.getElementsByTagName('canvas')[0];
  var ctx = can.getContext('2d');
  ctx.strokeStyle = '#600'; ctx.lineWidth = 2; ctx.lineJoin = 'round';
  ctx.fillStyle = '#ff0'
  document.body.onmousemove = function(evt){
    var w=140, h=120;
    var angle = evt ? (evt.pageX - can.offsetLeft)/100 : 0;
    angle = Math.max(Math.min(Math.PI/2,angle),0);
    ctx.clearRect(0,0,can.width,can.height); ctx.beginPath();
    ctx.save();
    ctx.translate(1,w*Math.sin(angle)+1);
    ctx.rotate(-angle);
    ctx.fillRect(0,0,w,h);
    ctx.strokeRect(0,0,w,h);
    ctx.restore();
  };
  document.body.onmousemove();
</script> 
</body></html>

Analysis

Rotate 'note' on the canvas to always touch the upper left corner

In the above diagram, point A is the upper-left corner of our post-it note and point B is the upper-right corner. We have rotated the post-it note -a radians from the normal angle (clockwise rotations are positive, counter-clockwise are negative).

We can see that the point A stays on the y axis as the post-it rotates, so we only need to calculate how far down the y axis to move it. This distance is expressed in the diagram as BD. From trigonometry we know that
sin(a) = BD / AB

Rearranging this formula gives us
BD = AB * sin(a)

We know that AB is the width of our post-it note. A few details:

  1. Because our angle will be expressed as a negative number, and the sin of a negative number yields a negative result, but because we want a positive result, we must either negate the result
    BD = -AB * sin(-a)
    or just 'cheat' and use a positive angle:
    BD = AB * sin(a)

  2. We need to remember to translate our context before we rotate it, so that we first move directly down the axis to establish our origin at the right spot.

  3. Remember that rotations in HTML5 Canvas use radians (not degrees). If you want to rotate by 20 degrees, you need to convert that to radians by multiplying by Math.PI/180:

     ctx.rotate( 20*Math.PI/180 );
    

This also applies to the arc command; you should be doing ctx.arc(x,y,r,0,Math.PI*2,false); for a full circle.


You should create you canvas element and then rotate it using CSS. It would keep your canvas intact and only rotate the element itself.

Here is some example css rules:

-webkit-transform: rotate(-30deg); 
-moz-transform: rotate(-30deg);

Refer to http://snook.ca/archives/html_and_css/css-text-rotation

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜