I try to add new SVG elements to some nodes. For that purpose the nodes the elements are to be added to have to be found by a string contained in there text content, e.g. find any node which has "id0"
inside the <text>
tag.
Here is example of my HTML hierarchy:
<pre>
<svg>
<g>
<g>
<text> id3 </text>
<text> 73% </text>
<svg> ... </svg>
</g>
<g>
<svg> ... </svg>
</g>
<g>
<text> id0 </text>
<text> 11% </text>
<svg> ... </svg>
</g>
<g>
<text> id1 </text>
<text> 66% </text>
<svg> ... </svg>
</g>
<g>
<svg> ... </svg>
</g>
</g>
</svg>
</pre>
I definitely don't know the right solution, but I think it is something like this:
d3.select('svg').select('g').selectAll('g').each(function (d, i) {})
.select('g').select('text').filter(function () {
return (d3.select(this).text() === 'id0')
})
.select(function () {
return this.parentElement;
})
.append('svg')
.attr('width', 400)
.attr('height', 400)
If the tag <text>
contains "id0"
, then return to the parent node and add an SVG element to it. But on the line return this.parentElement;
an error occurs:
Property 'parentElement' does not exist on type 'Window'.
Similar errors occur when I use parentElement
or parent
.
The easiest way to find an HTML element in the DOM, is by using the element id.
You can select an element based on its unique ID with the getElementById() method. This is the easiest way to find an HTML element in the DOM tree.
An alternative is xpath, which permits searching via text:
// if you know there's only one...
const singleResult = document.evaluate(`//*[name()="text" and contains(text(), "id0")]`, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
console.log(singleResult.nodeName, singleResult.textContent)
// if there might be multiple results
const multipleResults = document.evaluate(`//*[name()="text" and contains(text(), "id_multiple")]`, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
for (let i=0; i < multipleResults.snapshotLength; i++) {
console.log(multipleResults.snapshotItem(i).nodeName, multipleResults.snapshotItem(i).textContent)
}
<svg>
<g>
<g>
<text> id_multiple </text>
<text> 73% </text>
<svg></svg>
</g>
<g>
<svg></svg>
</g>
<g>
<text> id0 </text>
<text> 11% </text>
<svg></svg>
</g>
<g>
<text> id_multiple </text>
<text> 66% </text>
<svg></svg>
</g>
<g>
<svg></svg>
</g>
</g>
</svg>
The iterators (/snaphots) that are returned are unexpected for me - definitely have a read of this excellent answer: https://stackoverflow.com/a/32468320/2586761, and the docs: MDN: document.evaluate.
Note that because "common HTML nodes and svg nodes belong to different namespaces", you need to select SVG nodes like *[name()="svg"]
.
Regarding finding the text, I'd recommend using contains(text(),'needle')
rather than the more explicit text()='needle'
because any whitespace around needle
would cause the selector to return null
.
Interesting xpath vs CSS commentary: What is the difference between cssSelector & Xpath and which is better with respect to performance for cross browser testing?
Note that there's no IE support for document.evaluate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With