在画布中多次旋转单行

时间:2018-09-11 23:07:06

标签: rotation html5-canvas html5-video translation shapes

下面的代码几乎可以用,但是我想通过使用单个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>

3 个答案:

答案 0 :(得分:1)

好像您想画出一些阳光,并发出光线。

这是一种比您的代码少得多的选项,关键是使用函数来绘制图形

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



使用相同的功能和一些数学技巧,您可以绘制一些更复杂的形状,例如像这样的贝壳:

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
const p200 = Math.PI * 200

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

function shell(ini, end, mid) {
  ctx.lineWidth = 5;
  ctx.strokeStyle="black";
  for (i = ini; i < end; i += p200 / 124)
    drawLine(Math.cos(i/100),  Math.sin(i/100), mid - i/10);

  ctx.translate(-3, -3) 
  ctx.strokeStyle="cyan";
  for (i = ini; i < end; i += p200 / 96)
    drawLine(Math.cos(i/100),  Math.sin(i/100), mid - i/10);

  ctx.strokeStyle="blue";
  for (i = ini; i < end; i += p200 / 48)
    drawLine(Math.cos(i/100),  Math.sin(i/100), mid - i/10);     

  ctx.lineWidth = 0.5;
  ctx.strokeStyle="green";
  for (i = ini; i < end; i += p200 / 48)
    drawLine(Math.cos(i/100),  Math.sin(i/100), mid - i/10);
}


ctx.translate(70, 60) 
shell(0, p200, 95)

ctx.translate(200, 40) 
shell(p200/1.8, p200+p200/1.8, 135)
<canvas id="canvas" width="340" height="170">

答案 1 :(得分:1)

扫一条线

如果您想沿直线(与方向成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),其中rotate以弧度为单位(我将不使用度数),distance以像素为单位,scale > 1将增加该行,{ {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; ,然后将startAnglearcRadius沿该新角度移动到新中心。

arcCenter

有了中心的新位置,我们可以更改线的大小并在获得线的长度的同时旋转它。

         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;
   col = "hsl("+hue+","+s+"%,"+l+"%)";
}
    
canvas { position : absolute; top : 0px; left : 0px; }

答案 2 :(得分:0)

如果对结果满意,可以编写如下函数:

function drawLine(t,r, p1,p2){
//t: translation object 
//r: rotation object
//p1: point  object for the moveTo() method
//p2: point  object for the lineTo() method
    //ctx.save();
    ctx.beginPath();
    ctx.translate(t.x, t.y)
    ctx.rotate(r * Math.PI / 180);
    ctx.moveTo(p1.x, p1.y);
    ctx.lineTo(p2.x, p2.y);
    ctx.stroke();
    //ctx.restore();
}

由于您不使用保存和恢复方法,因此我已将其注释掉,但是这些方法非常有用,可以帮助您节省大量计算。