在画布中多次旋转一行

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在画布中多次旋转一行相关的知识,希望对你有一定的参考价值。

下面的代码几乎没问题,但我想通过使用单个makeline()函数使其简短,以避免重复代码行。我希望加载图像保持相同只是我希望代码简短。通过使用上述功能。正如您在下面看到的那样,代码太长了,当它运行时,线路没有正确调整。我希望形状保持不变,线条的位置应该只是一点点的调整

<!DOCTYPE html>
<html>

<head>

    <style>
        myCanvas {
            border: 1px;
            background: rgba( 240, 238, 238, 0.898);
        }
    </style>

</head>

<body>

    <canvas id="canvas" width="1000" height="1000" style="border:  ">

</canvas>

    <script>
        var c = document.getElementById("canvas");
        var ctx = c.getContext("2d");
        ctx.lineWidth = 5;

        ctx.beginPath();
        ctx.translate(470, 470)
        ctx.rotate(15 * Math.PI / 180);
        ctx.moveTo(25, 45);
        ctx.lineTo(100, 150);
        ctx.stroke();

        ctx.beginPath();
        ctx.rotate(55 * Math.PI / 180);
        ctx.moveTo(35, 35);
        ctx.lineTo(100, 150);
        ctx.stroke();

        ctx.beginPath();
        ctx.rotate(45 * Math.PI / 180);
        ctx.moveTo(35, 35);
        ctx.lineTo(100, 150);
        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(45 * Math.PI / 180);
        ctx.moveTo(35, 35);
        ctx.lineTo(100, 150);

        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(50 * Math.PI / 180);
        ctx.moveTo(25, 35);
        ctx.lineTo(100, 150);

        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(50 * Math.PI / 180);
        ctx.moveTo(35, 35);
        ctx.lineTo(100, 150);

        ctx.stroke();

        ctx.beginPath();
        ctx.rotate(40 * Math.PI / 180);
        ctx.moveTo(35, 50);
        ctx.lineTo(100, 150);

        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(5 * Math.PI / 180);
        ctx.moveTo(35, 50);
        ctx.lineTo(100, 150);

        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(15 * Math.PI / 180);
        ctx.moveTo(35, 45);
        ctx.lineTo(100, 150);

        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(15 * Math.PI / 180);
        ctx.moveTo(35, 45);
        ctx.lineTo(100, 150);

        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(25 * Math.PI / 180);
        ctx.moveTo(35, 35);
        ctx.lineTo(100, 150);

        ctx.stroke();
        ctx.beginPath();
        ctx.rotate(45 * Math.PI / 180);
        ctx.moveTo(35, 35);
        ctx.lineTo(100, 150);

        ctx.stroke();

    </script>
</body>

</html>
答案

看起来你想要用光线射出某种太阳。

这是一个选项,代码比你的少得多,关键是使用一个函数来绘制

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var hw = c.width/2; 
var hh = c.height/2
ctx.translate(hw, hh)
ctx.lineWidth = 5;

function drawLine(x, y) {
  ctx.beginPath();
  ctx.moveTo(x * hw/3, y * hh/3);
  ctx.lineTo(x * hw, y * hh);
  ctx.stroke();
}

var p200 = Math.PI * 200
for (i = 0; i < p200; i += p200 / 12)
  drawLine(Math.sin(i/100),  Math.cos(i/100));
<canvas id="canvas" width="170" height="170">
另一答案

Sweep A Line

如果你想沿着它的法线移动线(从它的方向90度)并旋转它,同时这样做,下面将解释如何使用绝对定位(没有ctx.rotate调用)

一些实用程序函数入门。

// A Point also defines a vector.
const Point = (x,y) => ({x,y});
const Line = (p1, p2) => ({p1, p2});
const lengthOfVec = vec => (vec.x ** 2 + vec.y ** 2) ** 0.5;
const normalVec = line => { // normalize the line and return a vector
     const vec = Point(line.p2.x - line.p1.x, line.p2.y - line.p1.y);
     const length =lengthOfVec(vec);
     vec.x /= length;
     vec.y /= length;
     return vec;
}
const rotateVec90 = vec => ([vec.y, vec.x] = [vec.x, - vec.y], vec);

我们可以从由其终点p1p2定义的直线开始,并且该直线的法线是在该线的左侧90度处的向量。

我们将创建一个沿着这个法线移动线的函数,该函数也会像它一样旋转线,并且通过示例的外观,线也需要更改长度,因此我们也可以添加一个scale参数。

步骤

函数将是sweepLine(line, distance, rotate, scale),whererotate是弧度(我不会使用度数),distance是像素,scale > 1将增长线和scale < 1将收缩线。

function sweepLine(line, dist, rot, scale){

我们需要线的中心和线标准化和正常作为矢量

    const center = Point((line.p1.x + line.p2.x) / 2, (line.p1.y + line.p2.y) / 2);
    const lineNorm = normalVec(line);
    const norm = rotateVec90(Point(lineNorm.x, lineNorm.y));

没有旋转

我们需要新的中心位置,如果我们正在旋转新的中心将在弧的末端,如果不旋转新的位置将在一条线的末尾。只需沿正常方向移动中心即可

    if(rot !== 0){
         // need the dist of point from center 
         const ax = line.p2.x - center.x;
         const ay = line.p2.y - center.y;

         // move the point
         center.x += norm.x * dist;
         center.y += norm.y * dist;

现在我们可以扩大规模

         line.p1.x = center.x - ax * scale 
         line.p1.y = center.y - ay * scale;
         line.p2.x = center.x + ax * scale;
         line.p2.y = center.y + ay * scale;
    }

旋转在弧上移动

对于旋转线,我们需要找到弧上的点,并定义弧,我们需要弧的中心。弧的长度是角度乘以半径的变化,我们没有半径

     else {
         const arcRadius = dist / rot;

弧中心距离中心的arcRadius距离(请注意,rot可以是负的,将中心移动到正确的位置)

         const arcCenter = Point(
             center.x + lineNorm.x * arcRadius,
             center.y + lineNorm.y * arcRadius
         );

现在我们有中心,我们需要弧的起始角度,这是线的方向。

         const startAngle = Math.atan2(lineNorm.y, lineNorm.x);
         const endAngle = startAngle + rot;

我们将旋转添加到startAngle,然后将arcRadiusarcCenter沿新角度移动到新中心。

         center.x = arcCenter.x + Math.cos(endAngle) * arcRadius;             
         center.y = arcCenter.y + Math.sin(endAngle) * arcRadius;

使用中心的新位置,如果我们得到线的长度,我们可以改变线的大小并同时旋转它。

         const len = lengthOfVec(Point(line.p1.x - line.p2.x, line.p1.y - line.p2.y));

         line.p1.x = center.x - Math.cos(endAngle) * len * scale * 0.5;
         line.p1.y = center.y - Math.sin(endAngle) * len * scale * 0.5;
         line.p2.x = center.x + Math.cos(endAngle) * len * scale * 0.5;
         line.p2.y = center.y + Math.sin(endAngle) * len * scale * 0.5;

就是这样。该功能可以返回。

    }
}

为了显示用法示例,下面的代码段执行相同但在此过程中进行了一些优化。

该示例创建一个随机行,然后使用sweepLine函数移动它。它是动画连续绘制线条。

requestAnimationFrame(update);

const ctx = canvas.getContext("2d");

var w = canvas.width;
var h = canvas.height;
function update(timer){
    if(w !== innerWidth || h !== innerHeight){
        w = canvas.width = innerWidth;
        h = canvas.height = innerHeight;
    }
    jiggle();	
    sweepLine(line, moveBy,rotateBy, scaleBy);
    drawLine(line);
    requestAnimationFrame(update);
}


// A Point also defines a vector.
const Point = (x,y) => ({x,y});
const Line = (p1, p2) => ({p1, p2});
const lengthOfVec = vec => (vec.x ** 2 + vec.y ** 2) ** 0.5;
const normalVec = line => { // normalize the line and return a vector
     const vec = Point(line.p2.x - line.p1.x, line.p2.y - line.p1.y);
     const length = lengthOfVec(vec);
     vec.x /= length;
     vec.y /= length;
     return vec;
}
const rotateVec90 = vec => {
    const t = vec.x;
    vec.x = - vec.y; 
    vec.y = t;
    return vec;
}




function sweepLine(line, dist, rot, scale){
    const center = Point((line.p1.x + line.p2.x) / 2, (line.p1.y + line.p2.y) / 2);
    const len = lengthOfVec(Point(line.p1.x - line.p2.x, line.p1.y - line.p2.y));
    const lineNorm = normalVec(line);
    const norm = rotateVec90(Point(lineNorm.x, lineNorm.y));
    if(rot === 0){
         const ax = (line.p2.x - center.x) * scale;
         const ay = (line.p2.y - center.y) * scale;
         center.x += norm.x * dist;
         center.y += norm.y * dist;
         line.p1.x = center.x - ax 
         line.p1.y = center.y - ay;
         line.p2.x = center.x + ax;
         line.p2.y = center.y + ay;
    } else {
         const arcRadius = dist / rot;
         const arcCenter = Point(
             center.x - lineNorm.x * arcRadius, center.y - lineNorm.y * arcRadius
         );
         const endAngle = Math.atan2(lineNorm.y, lineNorm.x) + rot;
         var ax = Math.cos(endAngle);
         var ay = Math.sin(endAngle);
         center.x = arcCenter.x + ax * arcRadius;             
         center.y = arcCenter.y + ay * arcRadius;
         const len = lengthOfVec(Point(line.p1.x - line.p2.x, line.p1.y - line.p2.y));
         ax *= len * scale * 0.5;
         ay *= len * scale * 0.5;
         line.p1.x = center.x - ax;
         line.p1.y = center.y - ay;
         line.p2.x = center.x + ax;
         line.p2.y = center.y + ay;
    }
}



function drawLine(line){
    ctx.lineWidth = 8;
    ctx.lineCap = "round";  
    ctx.strokeStyle = col;
    ctx.beginPath();
    ctx.lineTo(line.p1.x, line.p1.y);
    ctx.lineTo(line.p2.x, line.p2.y);
    ctx.stroke();
}


function createRandomLine(){
    const x = Math.random() * w * 0.3 + w * 0.35;
    const y = Math.random() * h * 0.3 + h * 0.35;
    const len = Math.random() * 40 + 10;
    const dir = Math.random() * Math.PI * 2; 
    return Line(
        Point(x - Math.cos(dir) * len * 0.5, y - Math.sin(dir) * len * 0.5),
        Point(x + Math.cos(dir) * len * 0.5, y + Math.sin(dir) * len * 0.5)
    );
}


// sweep the line randomly needs some settings
var line, rotateBy, moveBy, scaleBy, col, l = 50,s = 70,hue = 0,moveFor = 0; //
function randomize(){
  rotateBy = Math.random() * 0.5 - 0.25;
  moveBy = Math.random() * 5 + 5;
  scaleBy = 1;
  moveFor = 200; 
  line = createRandomLine();

}
function jiggle(){
   if(moveFor === 0 ){ randomize() }
   rotateBy += (Math.random() - 0.5) * 0.2;

   scaleBy = Math.random() < 0.2 ? 1/1.1 : Math.random() < 0.2 ?  1.1 : 1;
   moveBy +=  (Math.random() - 0.5) * 4;
   moveFor --;
   hue = (hue + 1) % 360;
   s = (s + 100  + Math.random() - 0.5) % 100;
   l = (l + 100  + Math.random() - 0.5) % 100;
   c

以上是关于在画布中多次旋转一行的主要内容,如果未能解决你的问题,请参考以下文章

多次调用片段 onCreateView

在 xamarin.android 中管理屏幕旋转时的片段外观

JS中canvas画布绘制中如何实现缩放,位移,旋转

如何以正确的方式旋转画布

如何以正确的方式旋转画布

处理屏幕旋转上的片段重复(带有示例代码)