Что делает быстро? fillRect () против moveTo (), lineTo (), stroke ()? - PullRequest
0 голосов
/ 27 февраля 2020

У меня есть устаревший код, где временная шкала для видео рендеринга с использованием Canvas (как я понял, это быстрее, чем рендеринг DOM). Итак, автор написал код методом fillRect(), но позже переписал его в комбинацию moveTo(), lineTo(), stroke().

. График времени выглядит как прямоугольник 8 * 1000 пикселей и может состоять из сотен прямоугольников. Я не могу спросить его, почему он сделал эти изменения, и у меня есть мнение, что лучше использовать fillRect().

Рендерится ли fillRect() так же быстро, как линии (с заливкой внутри)?

1 Ответ

0 голосов
/ 27 февраля 2020

Второй метод почти всегда будет быстрее.

Пока ему действительно не нужно рисовать что-то, все, что делает API контекста, это простая арифметика c, все на процессоре, и это довольно быстро.
Что занимает много времени это все сложная часть рисования + композитинг.
Как правило, чтобы сделать эту медленную часть быстрее, браузеры переместят эту часть в графический процессор. Но все равно нужно переместить все данные из оперативной памяти в память графического процессора, и это занимает некоторое время.

Таким образом, создание сложной фигуры на ЦП с использованием методов манипуляции путями и вызовом fill() или stroke() только один раз будет определенно быстрее, чем создание одного и того же сложного пути при вызове этих fill() и * 1012. * несколько раз, как fillRect или strokeRect обязаны делать.

const rects = Array.from({ length: 300 }, (_) => ({
  x: Math.random() * 1000,
  y: Math.random() * 1000,
  s: Math.random() * 200 + 50
}));
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

// Benchmark.js playground borrowed from 
// https://jsfiddle.net/533hc71h/

var test1_name = 'fillRect';
function test1() {
  rects.forEach(({ x, y, s }) => ctx.fillRect(x, y, s, s));
}
var test2_name = 'path + fill()';
function test2() {
  ctx.beginPath();
  rects.forEach(({ x, y, s }) => ctx.rect(x, y, s, s));
  ctx.fill();
}

function teardown() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}

var cycleResults = document.getElementById('cycleResults');
var result = document.getElementById('result');
var btn = document.getElementById('btn');

// BENCHMARK ====================
btn.onclick = function runTests() {

  btn.setAttribute('disable', true);
  cycleResults.innerHTML = '';
  result.textContent = 'Tests running...';

  var suite = new Benchmark.Suite;

  // add tests
  suite
    .add(test1_name || 'test1', test1)
    .add(test2_name || 'test2', test2)
    // add listeners
    .on('cycle', function(event) {
      var result = document.createElement('li');
      result.textContent = String(event.target);

      document.getElementById('cycleResults')
        .appendChild(result);
    })
    .on('complete', function() {
      result.textContent = 'Fastest is ' + this.filter('fastest').pluck('name');
      btn.setAttribute('disable', false);
      teardown();
      test2();
    })
    .run({
      async: true
    });
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/1.0.0/benchmark.min.js"></script>

<ul id='cycleResults'>

</ul>
<div id="result">

</div>
<br>
<button id="btn">
Run Tests
</button><br>

<canvas id="canvas" width="1000" height="1000"></canvas>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...