вращение одной строки несколько раз в холсте - PullRequest
0 голосов
/ 12 сентября 2018

приведенный ниже код почти идеален, но я хочу сделать его коротким и простым, используя одну функцию 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 голосов
/ 12 сентября 2018

Похоже, вы хотите нарисовать какое-то солнце с лучами, выходящими из него.

Вот один вариант с гораздо меньшим количеством кода, чем у вас, ключ в том, чтобы использовать функцию для рисования

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">
0 голосов
/ 15 сентября 2018

Sweep A Line

Если вы хотите переместить линию вдоль ее нормали (на 90 градусов от ее направления) и повернуть ее, при этом следующее объяснит, как это сделать, используя абсолютное позиционирование (нет * 1003).* звонки)

Некоторые служебные функции для начала работы.

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

Мы можем начать с линии, определяемой ее конечными точками p1 и p2, а нормаль к линии - это вектор, который находится под углом 90 градусов слева от линии.

Мы создадим функцию, которая перемещала линию вдоль этой нормали, функция также будет вращать линию, как это происходит, и, судя по вашему примеру, линия также должна изменить длину, чтобы мы могли добавитьАргумент масштабирования.

Шаги

Функция будет sweepLine(line, distance, rotate, scale), где rotate в радианах (я не буду использовать градусы), 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));

Нетrotate

Нам нужна новая позиция центра, если мы вращаемся, новый центр будет в конце дуги, если не вращать, новая позиция будет в конце линии.Просто переместите центр по обычной

    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, а затем переместите arcRadius расстояние от 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; }
<canvas id="canvas"></canvas>
0 голосов
/ 12 сентября 2018

Если вы довольны результатом, вы можете написать такую ​​функцию:

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

Я закомментировал методы сохранения и восстановления, поскольку вы их не используете, но эти методыочень полезно и поможет вам сэкономить много расчетов.

...