Вы получаете text
элементы, вложенные в элемент rect
из-за цепочки методов D3, где функции возвращают элемент, с которым работали (если функции используются для установки значения).Это означает, что когда у вас есть цепочка функций, похожих на ваши (здесь упрощенно):
.append('g')
...
.selectAll('rect').data([data]).enter()
.append('rect')
...
.append('text')
Затем вы сначала добавляете g
, затем добавляете элемент rect
для каждой точки данных в вашем массиве, прежде чем наконец добавить элемент text
к каждомуrect
element
Есть несколько способов добраться туда, где вы хотите быть.При этом вы не получите точное представление DOM, которое вы наметили, но вы можете добиться того же эффекта.
Я бы порекомендовал объединить элементы rect
и text
попарно в элемент g
для каждой точки данных, например:
const outerG = g.append('g')
.selectAll('g')
.data(data)
.enter()
.append('g')
.attr('transform', d => 'translate(' + x0(d.State) + ',0)')
const pairG = outerG.selectAll('g')
.data(d => keys.map(key => {return {key: key, value: d[key]}}))
.enter().append('g')
pairG.append('rect')
.attr('x', d => x1(d.key))
.attr('y', d => y(d.value))
.attr('width', x1.bandwidth())
.attr('height', d => innerHeight - y(d.value))
.attr('fill', d => z(d.key))
pairG.append('text')
.text(function(d) { return d.value; })
Сначала будет добавлен элемент g
для каждой точки данных и сохранена ссылка на эти элементы g
в pairG
.Затем мы добавляем элемент rect
и элемент text
индивидуально к переменной pairG
.Это работает, потому что D3 делает точки данных, используемые для добавления предыдущего g
, доступными для элементов rect
и text
.Если бы мы делали новую последовательность .selectAll('foo').data([data]).enter().append('foo')
, это было бы не так, поскольку это привело бы к появлению новых точек данных.
Код, который я вставил, должен работать с вашими данными и настройкой, хотя я не могуконечно, поскольку у меня нет доступа к данным, шкалам и переменным, которые вы используете.