创建不含中间字符串的复杂SVG



我正在创建/编辑svg路径元素的大量(100至1000秒(,并带有整数坐标,以响应用户输入(拖动(。

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

我可以并且可以汇总路径元素,因此它可以最大程度地减少对象的创建 垃圾。但是,似乎通过重复使用+=创建了许多中间字符串。另外,将坐标作为数字,将它们转换为字符串似乎有些奇怪,然后系统必须将它们解析为内部数字。

这似乎有些浪费,我担心jank,因为在每个鼠标库时都会重复上述内容。可以避免上述任何一个吗?


上下文:这是http://project.charemza.name/的一部分,在https://github.com/michalc/projections上的来源,可以在将Mercator投影应用于它之前旋转世界地图。

尝试以下:

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

有一种方法,使用 Uint8ArrayTextDecoder似乎比firefox中的字符串串联更快,但比chrome中的字符串串联慢:https://jsperf.com/integer-com/integer-coordinates-comeordinates-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);

最新更新