javascript - Bir listede sondan bir önceki etiketi nasıl seçerim?


Ben frontend geliştirmeye ve d3.js ile çalışmaya yeniyim. Bir dizi etiket içinde belirli bir etiketi seçme konusunda bir sorunum var.

Bazı grafikler oluşturdum ve belirli düğümlere bir resim eklemem gerekiyor. Gerekli etiketi d3.select('g') ile seçmeye çalıştım, ama bu ilk etiketi seçiyor. Ama bence asıl büyük problem, etiketlerin aynı isimde olması ve örneğin sondan bir önceki etiketi nasıl seçeceğimi bilmemem.

İşte benim HTML kodum (kısa versiyon):

<svg _ngcontent-c1="" width="1366" height="99">
   <gr _ngcontent-c1="" ng-reflect-zoomable-of="[object SVGSVGElement]">
      <g _ngcontent-c1="" _nghost-c2="" ng-reflect-link="[object Object]">
         <line _ngcontent-c2="" class="link" x1="1" y1="-2" x2="3" y2="-1"> </line>
      </g>
      <g _ngcontent-c1="" _nghost-c2="" ng-reflect-link="[object Object]">
         <line _ngcontent-c2="" class="link" x1="5" y1="2" x2="9" y2="4"> </line>
      </g>

   <g _ngcontent-c1="" ng-reflect-node="[object Object]" ng-reflect-draggable-node="[object Object]" ng-reflect-draggable-in-graph="[object Object]">
      <g transform="translate(3,4)">
         <text class="node-name" x="13" y="-3" font-size="20px">one</text>
      </g>
   </g>

   <g _ngcontent-c1="" ng-reflect-node="[object Object]" ng-reflect-draggable-node="[object Object]" ng-reflect-draggable-in-graph="[object Object]">
      <g transform="translate(5,6)">
             <text class="node-name" x="13" y="-3" font-size="20px">two </text>
          </g>
       </gr>

Ve bir resim ekleme girişimim:

var svg = d3.select('svg').select('gr').select('g')
  .append('svg')
  .attr('width', 64)
  .attr('height', 64)
  .style('border', '1px solid black');
var imgs = svg.selectAll('image').data([0]);
imgs.enter()
  .append('image')
  .attr('xlink:href', '/assets/ToNode.png')
  .attr('width', '64')
  .attr('height', '64');

Cevap #1

Sadece başlığa bakarak, sorunuzun bir tekrar olduğunu söyleyebiliriz, :last-child bariz bir tercih olarak öne çıkıyor. Bunun gibi birkaç tekrar hedefi var. Ancak, sondan bir önceki öğeyi nasıl seçeceğini gösteren bir cevap yok. Aslında, d3.js etiketi içinde penultimate ararsanız, sorunuz tek sonuç olarak karşınıza çıkıyor.

Belirli bir indeksle bir öğe seçmek için :nth-child() en yaygın seçenektir veya sondan sayıyorsanız :nth-last-child(). Ancak size ikinci ve üçüncü parametrelerin (çoğu D3 yönteminde) birlikte nasıl kullanılacağını gösteren bir cevap vermek istiyorum.

Birkaç D3 yönteminde (bu yanıtta kullanacağım filter gibi), ikinci parametre öğenin seçime göre indeksidir, üçüncü parametre ise o seçimi oluşturan mevcut grup veya düğümlerdir. Bu parametreler genellikle i ve n olarak adlandırılır, ancak onları istediğiniz şekilde adlandırabilirsiniz. Buradaki önemli bilgi, n.length ile bize öğelerin sayısını verdiğidir.

Yani, tüm <g> öğelerini seçersek, sondan bir önceki öğeyi şu şekilde alabiliriz:

yourSelection.filter(function(_, i, n) {
    return i === n.length - 2
  })

Burada, indeksler sıfır tabanlı olduğu için n.length - 2 kullanıyorum, bu nedenle n.length - 1 son elemandır. Ayrıca, _ sadece fonksiyonun herhangi bir yerinde ilk parametreyi kullanmadığımızı belirten bir konvansiyondur.

İşte bir demo, SVG'yi incelerseniz, sondan bir önceki gruba bir sahte öğe <foo> eklendiğini göreceksiniz:

d3.selectAll("g").filter(function(_, i, n) {
    return i === n.length - 2
  })
  .append("foo")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
  <g></g>
  <g></g>
  <g></g>
  <g></g>
  <g></g>
</svg>