创建没有中间字符串的复杂 SVG
Create complex SVG without intermediate strings
我creating/editing 大量(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);
我可以并且确实汇集了路径元素,因此它在这方面最大限度地减少了对象 + 垃圾的创建。但是,似乎很多中间字符串都是通过重复使用 +=
创建的。另外,将坐标作为数字,将它们转换为字符串,然后系统必须将它们 back 解析为内部数字似乎有点奇怪。
这似乎有点浪费,而且我担心卡顿,因为在拖动每只鼠标时都会重复上述操作。可以避免以上任何一种情况吗?
上下文:这是 http://projections.charemza.name/ 的一部分
,来源 https://github.com/michalc/projections,可以在应用墨卡托投影之前旋转世界地图。
试试这个:
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(''));
有一种方法,使用 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);
我creating/editing 大量(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);
我可以并且确实汇集了路径元素,因此它在这方面最大限度地减少了对象 + 垃圾的创建。但是,似乎很多中间字符串都是通过重复使用 +=
创建的。另外,将坐标作为数字,将它们转换为字符串,然后系统必须将它们 back 解析为内部数字似乎有点奇怪。
这似乎有点浪费,而且我担心卡顿,因为在拖动每只鼠标时都会重复上述操作。可以避免以上任何一种情况吗?
上下文:这是 http://projections.charemza.name/ 的一部分 ,来源 https://github.com/michalc/projections,可以在应用墨卡托投影之前旋转世界地图。
试试这个:
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(''));
有一种方法,使用 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);