Создать сложный SVG без промежуточных строк - PullRequest
0 голосов
/ 28 апреля 2018

Я создаю / редактирую множество (от 100 до 1000 с) элементов пути SVG с целочисленными координатами в реальном времени в ответ на ввод пользователя (перетаскивание).

var pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
var coords = [[0,0], [1,0], [1,1], [0,1]]; // In real case can be list of 1000s, dynamically generated

var d = '';
for (var i = 0; i < coords.length; ++i) {
  d += (i == 0 ? 'M' : 'L') + coords[i][0] + ',' + coords[i][1];
}
d += 'z';

pathElement.setAttributeNS(null, 'd', d);

Я могу и делаю пул элементов пути, так что это минимизирует создание объектов + мусор в этом отношении. Однако, похоже, что много промежуточных строк создаются с повторным использованием +=. Кроме того, немного странно иметь координаты в виде чисел, преобразовывать их в строки, а затем система должна проанализировать их назад во внутренних числах.

Это кажется немного расточительным, и я боюсь рывка, так как это повторяется при перетаскивании для каждой мышиной мыши. Можно ли избежать всего вышеперечисленного?


Контекст: это часть http://projections.charemza.name/ , источник в https://github.com/michalc/projections,, который может вращать карту мира до применения к ней проекции Меркатора.

Ответы [ 2 ]

0 голосов
/ 28 апреля 2018

Существует метод, использующий Uint8Array и TextDecoder, который кажется быстрее, чем конкатенация строк в Firefox, но медленнее, чем конкатенация строк в Chrome: https://jsperf.com/integer-coordinates-to-svg-path/1.

Промежуточные строки не создаются, но они создают Uint8Array (представление повторно используемого ArrayBuffer)

Вы можете ...

  • Вручную найти символы ASCII из числа
  • Установить символы в Uint8Array
  • Используйте new TextDecoder.decode(...., чтобы получить строку Javascript из буфера

Как показано ниже

// Each coord pair is 6 * 2 chars (inc minuses), commas, M or L, and z for path
var maxCoords = 1024 * 5;
var maxChars = maxCoords * (2 + 6 + 1 + 1) + 1
var coordsString = new Uint8Array(maxChars);
var ASCII_ZERO = 48;
var ASCII_MINUS = 45;
var ASCII_M = 77;
var ASCII_L = 76;
var ASCII_z = 122;
var ASCII_comma = 44;
var decoder = new TextDecoder();
var digitsReversed = new Uint8Array(6);

function concatInteger(integer, string, stringOffset) {
  var newInteger;
  var asciiValue;
  var digitValue;
  var offset = 0;

  if (integer < 0) {
    string[stringOffset] = ASCII_MINUS;
    ++stringOffset;
  }
  integer = Math.abs(integer);

  while (integer > 0 || offset == 0) {
    digitValue = integer % 10;
    asciiValue = ASCII_ZERO + digitValue;
    digitsReversed[offset] = asciiValue;
    ++offset;
    integer = (integer - digitValue) / 10;
  }

  for (var i = 0; i < offset; ++i) {
    string[stringOffset] = digitsReversed[offset - i - 1];
    ++stringOffset
  }

  return stringOffset;
}


var pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');

var coordsStringOffset = 0;
var coords = [[0,0], [1,0], [1,1], [0,1]]; // In real case can be list of 1000s, dynamically generated
for (var i = 0; i < coords.length; ++i) {
  coordsString[coordsStringOffset] = (i == 0) ? ASCII_M : ASCII_L;
  ++coordsStringOffset;
  coordsStringOffset = concatInteger(coords[i][0], coordsString, coordsStringOffset);
  coordsString[coordsStringOffset] = ASCII_comma
  ++coordsStringOffset;
  coordsStringOffset = concatInteger(coords[i][1], coordsString, coordsStringOffset);
}
coordsString[coordsStringOffset] = ASCII_z;
++coordsStringOffset;

var d = decoder.decode(new Uint8Array(coordsString.buffer, 0, coordsStringOffset));

pathElement.setAttributeNS(null, 'd', d);
0 голосов
/ 28 апреля 2018

Попробуйте это:

var pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
var coords = [[0,0], [1,0], [1,1], [0,1]]; // In real case can be list of 1000s, dynamically generated

var d = [];
for (var i = 0; i < coords.length; ++i) {
  d.push((i == 0 ? 'M' : 'L') + coords[i][0] + ',' + coords[i][1]);
}
d.push('z');

pathElement.setAttributeNS(null, 'd', d.join(''));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...