Могу ли я добавить буквальный элемент SVG с помощью d3?

#javascript #d3.js #svg

#javascript #d3.js #svg

Вопрос:

Я хотел бы добавить буквальный элемент SVG с помощью d3.

Поэтому вместо записи

 svg.selectAll("circle")            
    .data(data)                    
    .enter()                       
    .append("circle")    // etc etc
 

Я хотел бы сделать:

 svg.selectAll("circle")            
    .data(data)                    
    .enter()                       
    .append('<circle cx="158.9344262295082" cy="200" r="16" fill="red"></circle>')   
 

чтобы я мог создать сложный шаблон в другом месте (например, с помощью handlebars), а затем скомпилировать его с данными и добавить его.

Ответ №1:

Вы можете сделать это, хотя и не с помощью selection.append() функции. Вместо этого вам нужно будет использовать selection.html () функция.

Это сделало бы его довольно сложным для использования в контексте объединения данных, но не невозможным. Вероятно, это лучшее, что вы могли бы сделать, что включает в себя добавление дополнительной группы svg в DOM, что в любом случае может быть неплохо:

 var svg = d3.selectAll("svg");
svg.selectAll("circle")            
       .data([50, 100, 150])                    
       .enter()                       
       .append("g")
       .attr("transform", function(d) { return "translate("   [d, d]   ")"; })
       .html('<circle r="16" fill="red"></circle>');    
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="500" height="500"></svg> 

Я предполагаю, что, развивая этот ответ немного дальше, вы могли бы фактически встроить результат, который вы хотите отобразить, непосредственно в свой data объект. Итак, вы добавили некоторый код, который выглядел как:

.html(function(d) { return d.templatedHTML; });

Однако на этом этапе остановитесь и задайте себе вопрос: «Для чего я использую D3?». D3 описывается как

Документы, управляемые данными

Если вы используете что-то вроде handlebars , то вы убираете одну из основных обязанностей, для которых был разработан D3 (создание некоторого DOM из некоторых данных) и передаете его какой-либо другой библиотеке.

Я не утверждаю, что вы не должны этого делать (поскольку вы упомянули сложные шаблоны), но просто задайте себе вопрос, чтобы убедиться, что это путь, по которому вы хотите пойти.

Комментарии:

1. Спасибо за аккуратный, обстоятельный ответ. Я согласен, что мне следует подумать дважды — возможно, это просто когнитивные трения, которые возникают из-за очень функционального стиля в d3, к которому я не привык (пока).

2. @simone Нет проблем — если вы считаете, что ответ хорош, не стесняйтесь голосовать 😉 D3 требует небольшого обучения, но это очень мощная библиотека, когда вы научитесь с ней работать.

Ответ №2:

Нет, вы не можете. Не верите мне? Проверьте их документы ЗДЕСЬ

Что вам нужно сделать, это вызвать .append() , а затем несколько вызовов .attr(attr_name, attr_value) , чтобы установить значение каждого атрибута. D3 не работает как jQuery.

Ответ №3:

D3 не предоставляет такой функциональности, и это не имеет особого смысла (когда вы думаете о манипулировании элементами на основе данных).

Но, в качестве дополнительного примечания, вы можете реализовать свою собственную функцию для добавления литерального элемента SVG.

Это функция, созданная Крисом Виау, с именем appendSVG :

 d3.selection.prototype.appendSVG = 
    d3.selection.enter.prototype.appendSVG = function(SVGString) {
        return this.select(function() {
            return this.appendChild(document.importNode(new DOMParser()
                .parseFromString('<svg xmlns="http://www.w3.org/2000/svg">'   SVGString   
            '</svg>', 'application/xml').documentElement.firstChild, true));
        });
    };
 

После расширения прототипа вы можете использовать его:

 selection.appendSVG("<some literal SVG element>");  
 

Вот демонстрация. Сначала мы устанавливаем данные:

 var data = [{x:30,y:50},{x:420,y:100},{x:160,y:150},{x:260,y:30}];
 

Затем мы добавляем наш буквальный элемент SVG обычным способом:

 var myLiteral = svg.selectAll(".literal")
    .data(data)
    .enter()
    .appendSVG("<literal SVG here>");
 

И, наконец, мы устанавливаем позиции с помощью translate :

 .attr("transform", function(d){ 
    return "translate("   d.x   ","   d.y   ")";
});
 

Проверьте фрагмент:

 d3.selection.prototype.appendSVG = d3.selection.enter.prototype.appendSVG = function(SVGString) {return this.select(function() { return this.appendChild(document.importNode(new DOMParser().parseFromString('<svg xmlns="http://www.w3.org/2000/svg">'   SVGString   '</svg>', 'application/xml').documentElement.firstChild, true));});};

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

var data = [{x:30,y:50},{x:420,y:100},{x:160,y:150},{x:260,y:30}];
		
var myLiteral = svg.selectAll(".literal")
  .data(data)
  .enter()
  .appendSVG("<path d='M 22.889471,25.607172 C 22.589713,24.605127 24.092318,24.708731 24.554936,25.108955 C 25.808602,26.193538 25.053398,28.14136 23.885905,28.938102 C 21.797533,30.363287 19.018523,29.16303 17.893076,27.101823 C 16.241437,24.076919 17.936475,20.36976 20.896603,18.945312 C 24.841988,17.046747 29.504523,19.25402 31.216796,23.116087 C 33.371517,27.976105 30.644503,33.605344 25.878773,35.599962 C 20.106834,38.015712 13.505062,34.765112 11.231216,29.094691 C 8.551568,22.412295 12.327973,14.834577 18.903736,12.283452 C 26.495714,9.3380778 35.051552,13.641683 37.878656,21.12322 C 41.09099,29.624218 36.259254,39.159651 27.87164,42.261821 C 18.462006,45.741988 7.9459296,40.381466 4.5693566,31.087558 C 0.82072068,20.769559 6.7105029,9.2720694 16.910868,5.6215926' style='fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1'/>")
  .attr("transform", function(d){ return "translate("   d.x   ","   d.y   ")"}); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>