将画布上的“注释”旋转,使其始终触及左上角

3

最终对我起作用的代码是:

    <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>

你好,

我用html5的画布和一些js制作了一个快速而简单的“便笺”。

我想要能够任意旋转它们,所以我尝试使用translate。下面的示例中,我有一个0,250的translate,只是为了让你看到整个东西。

理想情况下,我知道如果我的画布是300,300,那么我会这样写: ctx.translate(150,150); ctx.rotate(-30); ctx.translate(-150,-150);

当然,因为我旋转的是一个正方形,所以它被切掉了。

我该如何旋转正方形并将其移动到画布的左上角,使整个图案都显示出来?

我添加了一张图片,展示了我的想法,只需获取三角形的高度并将其移动即可,但在翻译时,似乎不太对。

我将整个函数粘贴在这里,这样你就可以查看它,但如果你有任何想法,我会很感激。这不重要,只是今天闲着玩玩。

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);

HTML5画布中的便签


更多信息

Phrog,我认为你知道我想要做什么。这张图片展示了我想要做的事情: 输入图像描述 现在,唯一的问题是,我希望能够传入任何宽度、高度和角度,并实时进行调整。

例如,以下代码:

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();

我得到了以下图片: 在此输入图片描述 现在,如果我加入旋转效果,像这样:
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.translate(-25, -25);
ctx.arc(0,0,3,0,360,true); ctx.fill();

我现在得到的是倾斜的坐标结果: enter image description here 我发现这是因为坐标不再是水平和垂直的。
所以,对于这个旋转后的坐标结构,我无法想象如何将我的正方形(可以是任何大小和旋转角度)移回左上角(以使它尽可能地适合空间)。
这有意义吗?
2个回答

4
简而言之:
  • 仅在Y方向上翻译上下文以将角落放置在正确位置。
  • 围绕此偏移点旋转上下文。
  • 在0,0处绘制您的对象。
这里有一个互动的,可工作的例子,您可以在这里在线查看:
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>

分析

图表显示一个矩形逆时针旋转,其中角A在Y轴0,12处,角B在X轴20,0处;构造D位于20,12处,角DAB用小写字母'a'标记

在上图中,点A是我们便签的左上角,点B是右上角。我们将便签-a弧度从正常角度旋转(顺时针旋转为正,逆时针旋转为负)。

我们可以看到,随着便签的旋转,点A仍然停留在y轴上,因此我们只需要计算向下移动y轴的距离。这个距离在图中表示为BD。根据三角函数我们知道:
sin(a) = BD / AB

重排这个公式给我们
BD = AB * sin(a)

我们知道AB是我们便签的宽度。一些细节:

  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 );
    
这也适用于arc命令;对于完整的圆形,您应该执行ctx.arc(x,y,r,0,Math.PI*2,false)

这是在短时间内完成的出色工作。不幸的是,它并没有真正帮助我翻译新坐标的斜率。我刚刚意识到,当你旋转时,画布会将任何更多的平移解释为斜率而不是水平垂直方式。这让我感到非常困惑。也许是时候重新温习一下三角函数了。 - Senica Gonzalez
@SenicaGonzalez 在绘制旋转矩形后,您可以使用restore()恢复上下文,或者手动取消旋转,如果您不想继续在变换后的坐标系统中工作。遗憾的是,我不理解您所遇到的问题(我不知道“翻译新坐标系的斜率”是什么意思),但我很高兴您似乎已经找到了一个适合您的答案。 - Phrogz
@Phrogz。是的,我知道我可以恢复它或取消旋转,但我想保持矩形的旋转状态,只是像你在示例中展示的那样将其移回到左边缘和顶部边缘。然而,在我旋转矩形之后,x,y坐标与屏幕相对不是上下方向,坐标也被旋转了。因此,我试图弄清楚如何将我的旋转矩形和旋转坐标移到我想要的位置,但一直失败。 - Senica Gonzalez
@Senica 嗯,随时欢迎您发布一个更新的、不工作但是自包含的示例以获取进一步的帮助。(将代码精简到最小以展示问题会更容易协助您。) - Phrogz
@Senica 我已经更新了我的答案,并附上了我正在使用的代码推导。(我还更新了代码和示例,以使笔记的“顶部”指向角落。) - Phrogz
显示剩余5条评论

2

您应该创建Canvas元素,然后使用CSS旋转它。这样可以保持Canvas不变,并仅旋转元素本身。

以下是一些示例CSS规则:

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

请参考http://snook.ca/archives/html_and_css/css-text-rotation。该网页介绍了CSS文本旋转相关的内容。

我觉得这是一种不太正规的解决方法 ;) 但是考虑到我无法找出斜率坐标,现在只能这样做了。 - Senica Gonzalez
我认为这是更好的方法。在画布内旋转元素可能需要像素级别的操作(每个像素独立计算),因此会更加资源密集。而这种解决方案则可以旋转整个块,速度可能会更快。看来你能接受这种方式。 - tiagoboldt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接