2016-03-12 4 views
1

Во-первых, я использую d3.js и SVG. У меня есть этот фрагмент кода, который рисует путь:Альтернативный способ написать это?

var one = d3.select('#canvas1'); 
var oneCanvas = one.append("svg").attr("width", 200).attr("height", 190); 
oneCanvas.append("svg:path") 
     .attr("d", "M100 15 A 55 55, 0, 0, 0, 73 61 A 55 55, 0, 0, 1, 127 61 A 64 64, 0, 0, 0, 100 15") 
     .style("stroke","black") 
     .style("fill", "white") 
     .style("stroke-width", 1) 
     .on("click", function(){ 
      d3.select(this).style("fill", "magenta"); 
      alert("You've clicked on the path in the 1st div"); 
     });  

Я использую путь около 20 раз повсюду. При таком подходе я повторяю вышеуказанный код снова и снова, как показано в https://jsfiddle.net/s26kghmq/

Причина, по которой я не использую 'd3.selectAll', заключается в том, что при этом я не буду устанавливать различные функции при нажатии на этот путь.

Я реализовал SVG-х 'def' и 'use', но это не помогает мне тоже, потому что если я установил стиль ранее, я не могу переопределить его снова в 'use', как описано здесь: http://taye.me/blog/svg/a-guide-to-svg-use-elements/

Я интересно, есть ли альтернативный подход для достижения функциональности без повторения?

Заранее благодарим за все ваши ответы.

ответ

2

Это не имеет значения, если обратный вызов отличается в .on события, есть много способов справиться с этим. d3 - все о привязке данных, итерации и не дублирующий код. Итак, вы действительно, действительно должны использовать selectAll.

var data = [1,2]; 
 

 
var color = d3.scale.ordinal() 
 
    .domain(data) 
 
    .range(['magenta','yellow']); 
 

 
var one = d3.selectAll('.v1') 
 
    .data(data) 
 
    .append("svg") 
 
    .attr("width", 200) 
 
    .attr("height", 190) 
 
    .append("svg:path") 
 
    .attr("d", "M100 15 A 55 55, 0, 0, 0, 73 61 A 55 55, 0, 0, 1, 127 61 A 64 64, 0, 0, 0, 100 15") 
 
    .style("stroke","black") 
 
    .style("fill", "white") 
 
    .style("stroke-width", 1) 
 
    .on('click', function(d){ 
 
    d3.select(this).style("fill", color(d)); 
 
    alert("You've clicked on the path in the " + d + " div"); 
 
    });
.v1{ 
 
    width: 200px; 
 
    height: 100px; 
 
    background: white; 
 
    border: 1.5px solid #000000; 
 
} 
 

 
#canvas2{ 
 
    position: absolute; 
 
    top: 150px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="canvas1" class="v1"></div> 
 

 
<div id="canvas2" class="v1"></div>


Обновления для комментариев

Если обратные вызовы являются уникальными в ИГД тогда они тоже просто становятся атрибутами данных. Кроме того, вы можете всегда сегмент из общих и конкретной функциональности:

function sharedFunc(elem,d){ 
 
    d3.event.stopPropagation(); 
 
    d3.select(elem).style('fill', d.color); 
 
} 
 

 
var data = [ 
 
    { 
 
    specificFunc: function(d){ 
 
     alert("you've clicked the 1st one"); 
 
    }, 
 
    color: 'magenta' 
 
    },{ 
 
    specificFunc: function(d){ 
 
     alert("you've clicked the 2nd one"); 
 
    }, 
 
    color: 'yellow' 
 
    } 
 
]; 
 

 
d3.selectAll('.v1') 
 
    .data(data) 
 
    .append("svg") 
 
    .attr("width", 200) 
 
    .attr("height", 190) 
 
    .append("svg:path") 
 
    .attr("d", "M100 15 A 55 55, 0, 0, 0, 73 61 A 55 55, 0, 0, 1, 127 61 A 64 64, 0, 0, 0, 100 15") 
 
    .style("stroke","black") 
 
    .style("fill", "white") 
 
    .style("stroke-width", 1) 
 
    .on('click', function(d){ 
 
    sharedFunc(this, d); 
 
    d.specificFunc(d); 
 
    }); 
 

 
$("#canvas1").click(function(){ 
 
    alert("you clicked on the canvas"); 
 
});
.v1{ 
 
    width: 200px; 
 
    height: 100px; 
 
    background: white; 
 
    border: 1.5px solid #000000; 
 
} 
 

 
.v2{ 
 
    width: 200px; 
 
    height: 100px; 
 
    background: white; 
 
    border: 1.5px solid #000000; 
 
} 
 

 
#canvas2{ 
 
    position: absolute; 
 
    top: 150px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<div id="canvas1" class="v1"></div> 
 
<div id="canvas2" class="v1"></div>

+0

Спасибо за подробный ответ. Но что, если бы у меня были функции, определенные следующим образом: https://jsfiddle.net/s26kghmq/2/? Я редактировал код, чтобы показать результат. Это в конечном итоге приведет к дублированию, как я показал в обновленной скрипке? :) Если я не пропущу что-то ... – nicki

+0

@nicki, см. Обновления ... – Mark

+0

Perfect! Многому научился с этим вопросом. Спасибо! – nicki

2

Вы можете поместить путь рисунок в виде отдельной функции как таковой

var drawPath = function(ele, clickFunction){ 
    ele.append("svg:path") 
     .attr("d", "M100 15 A 55 55, 0, 0, 0, 73 61 A 55 55, 0, 0, 1, 127 61 A 64 64, 0, 0, 0, 100 15") 
     .style("stroke","black") 
     .style("fill", "white") 
     .style("stroke-width", 1) 
     .on("click", clickFunction) 
} 

и затем использовать эту функцию, как это:

oneCanvas.call(drawPath, yourSpecificClickFunction) 
+0

Спасибо за ваш ответ. Похоже, он должен решить мою проблему, но я не могу заставить ее работать. Может, я что-то упустил? Можете ли вы, пожалуйста, обновить скрипку? :) – nicki

+0

Я сделал скрипку, содержащую мои изменения здесь: https://jsfiddle.net/b3q93sea/, хотя ответ Marks также отлично подходит –

Смежные вопросы