Подтвердить что ты не робот

Как создать объект "svg", не добавляя его?

Рассмотрим следующий код:

var svg = d3.select('#somediv').append("svg").attr("width", w).attr("height", h);

Я хотел бы реорганизовать этот код так, чтобы он читал больше:

var svg = makesvg(w, h);
d3.select("#somediv").append(svg);

Обратите внимание, что в отличие от ситуации, показанной в первой версии, в этой второй версии append не создается объект "svg"; он добавляет его только к d3.select("#somediv").

Проблема заключается в том, как реализовать функцию makesvg. Это, в свою очередь, сводится к проблеме: как создать экземпляр объекта "svg" без использования append для этого, поскольку тогда можно было бы сделать что-то вроде:

function makesvg(width, height) {
  return _makesvg().attr("width", w).attr("height", h);
}

Итак, мой вопрос сводится к тому, что является общим эквивалентом гипотетического _makesvg() factory, упомянутого выше?

4b9b3361

Ответ 1

Вы можете использовать следующее:

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

Обратите внимание на использование createElementNS. Это необходимо, потому что элементы svg не находятся в том же пространстве имен XHTML, что и большинство элементов HTML.

Этот код создает новый элемент svg, так как вы независимо от использования D3 или нет, а затем создаете выделение по этому одиночному элементу.

Это можно сделать чуть более кратким, но более ясным и менее подверженным ошибкам:

var svg = document.createElementNS(d3.ns.prefix.svg, 'svg');

Ответ 2

Чтобы сэкономить немного времени, вы можете использовать d3.ns.prefix.svg

var svg = document.createElementNS(d3.ns.prefix.svg, 'svg');

Ответ 3

Здесь примерная функция, которая создает непривязанный элемент группы:

function createSomething(){
  return function(){
    var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
    // Add stuff...
    return group.node();
  }
}

Вы можете вызвать его так:

node.append(createSomething());

Объяснение

Скажем, вы создаете сбрасываемое дерево, и вы хотите иметь значки плюс/минус с круговой границей в качестве переключателей. Ваша функция рисования уже огромна, поэтому вам нужен код для рисования знака плюс в его собственной функции. Метод draw/update позаботится о правильном позиционировании.

Один из вариантов - передать существующий контейнер в функцию:

createPlus(node).attr({
  x: 10,
  y: 10
});

function createPlus(node){
  var group = node.append('g');
  // Add stuff...
  return group;
}

Мы можем сделать это лучше, применив технику от @Drew и @Paul для создания непривязанных элементов.

node.append(createPlus())
    .attr({
      x: 10,
      y: 10
    });

function createPlus(){
  var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
  // Add stuff...
  return group;
}

Кроме того, что выдает ошибку, потому что append() ожидает либо строку, либо функцию.

Имя может быть указано как константная строка или как функция, которая возвращает элемент DOM для добавления.

Итак, мы просто меняем его на:

node.append(function(){
  return createPlus();
});

Но это все еще не работает. Это вызывает следующую ошибку:

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.

К счастью, я нашел selection.node(), который работает! Хотя, по общему признанию, я понятия не имею, почему.

function createPlus(){
  var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
  // Add stuff...
  return group.node();
}

Мы можем сэкономить немного времени, переместив анонимную функцию в createPlus:

node.append(createPlus())

function createPlus(){
  return function(){
    var group = d3.select(document.createElementNS(d3.ns.prefix.svg, 'g'));
    // Add stuff...
    return group.node();
  }
}

Ответ 4

D3 автор Майк Босток предлагает другой (более простой) подход в своем комментарии к старой проблеме D3 Github, спрашивая об этой самой теме:

Еще одна стратегия, которую вы могли бы рассмотреть, - удалить элемент из DOM сразу после его создания:

var svg = d3.select("body").append("svg")
    .remove()
    .attr("width", w)
    .attr("height", w);

svg.append("circle")
    .attr("r", 200);

document.body.appendChild(svg.node());

Этот подход действительно добавляет элемент при создании, но .remove он непосредственно перед манипуляцией и созданием дочерних элементов, поэтому не должно быть перерисовки браузера. Хотя это технически противоречит исходному вопросу, это, вероятно, самый идиоматический способ удовлетворить это требование.

Ответ 5

Я работаю с версией 4.4.4

var svg = document.createElementNS(d3.namespaces.svg, "svg");