Canvas рисует один раз с переводом и один раз без ошибок

#javascript #html #canvas

#javascript #HTML #холст

Вопрос:

Я предпринял почти все возможные контрмеры, чтобы моя программа не нарисовала на моем графике две точки вместо одной. Я хочу, чтобы была показана точка в середине, а не та, что в левом верхнем углу. Мне кажется, что точка рисуется один раз в верхнем левом углу, сопоставляя координаты и все остальное, но затем она рисует вторую точку с помощью translate метода. Конечно, это всего лишь предположение о том, что происходит на экране. Проблема возникает где-то в draw() функции, init() function или anim() функции — я не могу точно определить, в чем проблема.

 let graph = document.getElementById('chart');
let c = graph.getContext('2d');
graph.height = 754;
graph.width = 754;

function algebra() {

  xVertex = 2 * 10;
  yVertex = 5 * 10;

  let radius = 3;
  let node = [];


  function Node(xVertex, yVertex, radius) {
    this.r = radius;
    this.xV = xVertex;
    this.yV = yVertex;

    this.draw = function() {
      c.beginPath();
      c.arc(this.xV, this.yV, this.r, 0, Math.PI * 2, false);
      c.fillStyle = "red";
      c.fill();
      c.translate(377, 377);
      c.stroke();
      c.closePath();
    };

    this.update = function() {
      this.draw();

    };
  };

  function init() {
    node.push(new Node(xVertex, yVertex, radius));
    anim();
  };

  function anim() {
    requestAnimationFrame(anim);
    for (let i = 0; i < node.length; i  ) {
      node[i].update(node);
    };
    c.clearRect(0, 0, graph.width, graph.height);
    console.log(node);
  };
  init();
};  
 #graph {
  left: 100px;
  background-color: grey;
}  
 <!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title> Proof of concept </title>
  <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
  <div id="graph">
    <canvas id="chart"></canvas>
    <div id="y-axis"></div>
    <div id="x-axis"></div>
  </div>
  <div id="button" onclick="algebra()">
    <div id="btext">Calculate</div>
  </div>

  <script type="text/javascript" src="app.js"></script>
</body>

</html>  

Ответ №1:

Я думаю, что нашел ваши ошибки:

1) При вызове anim() он должен сначала очистить canvas, а затем перерисовать все точки.

2) Вызовите следующий кадр анимации после того, как все точки будут нарисованы на холсте

И основная проблема:

3) Вы выполняете перевод источника canvas для каждой нарисованной точки (и большой (377, 377)). Поскольку начало координат меняется при каждой итерации или нарисованной точке, перемещается и удаляемая часть холста. Две точки, которые вы получили, были первой и второй итерациями, остальные были за кадром.

Что вам нужно сделать, это перевести начало холста в его середину только один раз, сразу после:

 let c = graph.getContext('2d');
graph.height = 754;
graph.width = 754;

//Translate the origin to the canvas' center (do this only once)
c.translate(graph.width/2, graph.height/2);
  

Если начало координат холста переместилось в центр, то вы также должны стереть холст с -width /2 на width /2 и height /2 на height /2. Для этого вы должны использовать:

 c.clearRect(-graph.width/2, -graph.height/2, graph.width, graph.height);
  

Просто для удовольствия я добавил еще три точки к массиву узлов и добавляю случайное число от -1 до 1 к каждой координате на каждой итерации. Это приводит к моделированию броуновского движения.

 let graph = document.getElementById('chart');
let c = graph.getContext('2d');
graph.height = 754;
graph.width = 754;

//Translate the origin to the canvas' center (do this only once)
c.translate(graph.width/2, graph.height/2);


function algebra() {

  //Changed to 0 to plot at center
  xVertex = 0;
  yVertex = 0;

  let radius = 3;
  let node = [];


  function Node(xVertex, yVertex, radius) {
    this.r = radius;
    this.xV = xVertex;
    this.yV = yVertex;

    this.draw = function() {      
      c.beginPath();
      c.arc(this.xV, this.yV, this.r, 0, Math.PI * 2, false);
      c.fillStyle = "red";
      c.fill();
      c.stroke();
      c.closePath();
    };

    this.update = function() {
      //this will generate random movement in x and y.
      this.xV  = Math.random()*2-1;
      this.yV  = Math.random()*2-1;
      this.draw();
    };
  };

  function init() {
    node.push(new Node(xVertex, yVertex, radius));
    node.push(new Node(xVertex, yVertex, radius));
    node.push(new Node(xVertex, yVertex, radius));
    node.push(new Node(xVertex, yVertex, radius));
    anim();
  };

  function anim() {
    //First clear the canvas then redraw
    c.clearRect(-graph.width/2, -graph.height/2, graph.width, graph.height);
    for (let i = 0; i < node.length; i  ) {
      node[i].update(node);
    };
    //After all are drawn, call the next Animation Frame
    requestAnimationFrame(anim);
  };
  init();
};  
 #graph {
  left: 100px;
  background-color: grey;
}  
 <!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title> Proof of concept </title>
  <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
  <div id="graph">
    <canvas id="chart"></canvas>
    <div id="y-axis"></div>
    <div id="x-axis"></div>
  </div>
  <div id="button" onclick="algebra()">
    <div id="btext">Calculate</div>
  </div>

  <script type="text/javascript" src="app.js"></script>
</body>

</html>  

Комментарии:

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

2. Если вы хотите, чтобы центр постоянно переводился в середину холста, сделайте это сразу после сохранения getContext (‘2D’) и никогда не перемещайте его оттуда. Но для очистки холста вы должны нарисовать clearRect(-width/2, height/2, width, height)

3. Если вы перемещаете его после того, как каждая точка нарисована, то начало координат будет продолжать дрейфовать.

4. @MikhailYourchenko, я изменил ответ, чтобы указать источник translate() только один раз.

5. @MikhailYourchenko пожалуйста, примите ответ, если он решил вашу проблему