I am working with a svg element which is as follows
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="none" stroke="red"></rect>
<rect x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g style="transform: translate(70px, 70px);">
<g >
<g fill="none" font-size="10" font-family="sans-serif">
<g opacity="1" transform="translate(0,411.7647058823529)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">20%</text>
</g>
<g opacity="1" transform="translate(0,223.52941176470583)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">40%</text>
</g>
<g opacity="1" transform="translate(0,35.29411764705883)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">60%</text>
</g>
</g>
</g>
</g>
</svg>
</body>
<script type="text/javascript"></script>
</html>
With javascript, I intend to generate a svg
which will show each yAxis
grid line after the text. e.g.
To programmatically generate this, my approach was to generate a clipPath
with a rect
that starts at x=text.x text.width
and same y,width
as the lines and height=text.height
and have it apply on each line
.
This is what I tried so far
const svgns = 'http://www.w3.org/2000/svg';
document.querySelectorAll('.tick>line').forEach(
(a, i) => {
const defs = document.createElementNS(svgns, 'defs');
document.querySelector('svg').appendChild(defs);
const clipPath = document.createElementNS(svgns, 'clipPath');
clipPath.setAttribute('id', `clip${i}`);
defs.appendChild(clipPath);
const data = document.querySelectorAll('.tick>text');
const rect = document.createElementNS(svgns, 'rect')
rect.setAttribute('x', `${data[i].getBoundingClientRect().x data[i].getBoundingClientRect().width}`);
rect.setAttribute('y', `${a.getBoundingClientRect().y}`);
rect.setAttribute('height', `${data[i].getBoundingClientRect().height}`)
rect.setAttribute('width', `${a.getBoundingClientRect().width}`)
clipPath.appendChild(rect);
a.style.setProperty('clip-path', `url(#clip${i})`)
}
)
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="none" stroke="red"></rect>
<rect x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g style="transform: translate(70px, 70px);">
<g >
<g fill="none" font-size="10" font-family="sans-serif">
<g opacity="1" transform="translate(0,411.7647058823529)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">20%</text>
</g>
<g opacity="1" transform="translate(0,223.52941176470583)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">40%</text>
</g>
<g opacity="1" transform="translate(0,35.29411764705883)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">60%</text>
</g>
</g>
</g>
</g>
</svg>
</script>
</html>
I can't figure out what I am doing wrong in this. it does not return what I was intending.
Also, is there a built-in method currentyl exists in javascript
that does union/combine/intersect/subtract
operations of svg
elements?
CodePudding user response:
This worked for me
const svgns = 'http://www.w3.org/2000/svg';
document.querySelectorAll('.tick>line').forEach(
(a,i)=>{
const defs = document.createElementNS(svgns, 'defs');
document.querySelector('svg').appendChild(defs);
const clipPath = document.createElementNS(svgns, 'clipPath');
clipPath.setAttribute('id',`clip${i}`);
defs.appendChild(clipPath);
const data = document.querySelectorAll('.tick>text');
const rect = document.createElementNS(svgns, 'rect')
rect.setAttribute('x', `${data[i].getComputedTextLength()}`);
//rect.setAttribute('y', `${a.getBoundingClientRect().y}`);
rect.setAttribute('height', `${data[i].getBBox().height}`)
rect.setAttribute('width', `${a.x2.baseVal.value-a.x1.baseVal.value}`)
clipPath.appendChild(rect);
a.style.setProperty('clip-path',`url(#clip${i})`)
}
)
const svgns = 'http://www.w3.org/2000/svg';
document.querySelectorAll('.tick>line').forEach(
(a,i)=>{
const defs = document.createElementNS(svgns, 'defs');
document.querySelector('svg').appendChild(defs);
const clipPath = document.createElementNS(svgns, 'clipPath');
clipPath.setAttribute('id',`clip${i}`);
defs.appendChild(clipPath);
const data = document.querySelectorAll('.tick>text');
const rect = document.createElementNS(svgns, 'rect')
rect.setAttribute('x', `${data[i].getComputedTextLength()}`);
//rect.setAttribute('y', `${a.getBoundingClientRect().y}`);
rect.setAttribute('height', `${data[i].getBBox().height}`)
rect.setAttribute('width', `${a.x2.baseVal.value-a.x1.baseVal.value}`)
clipPath.appendChild(rect);
a.style.setProperty('clip-path',`url(#clip${i})`)
}
)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
<body>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect width="1280" height="720" fill="none" stroke="red"></rect>
<rect x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g style="transform: translate(70px, 70px);">
<g >
<g fill="none" font-size="10" font-family="sans-serif">
<g opacity="1" transform="translate(0,411.7647058823529)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">20%</text>
</g>
<g opacity="1" transform="translate(0,223.52941176470583)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">40%</text>
</g>
<g opacity="1" transform="translate(0,35.29411764705883)">
<line stroke="currentColor" x2="1160"></line>
<text fill="currentColor" x="0" dy="0.32em">60%</text>
</g>
</g>
</g>
</g>
</svg>
</body>
</html>
d3 equivalent
const clipRectData =d3.selectAll('.tick>text').nodes();
d3.select('svg')
.selectAll('defs')
.data(d3.selectAll('.tick>line'))
.join('defs')
.append('clipPath')
.attr('id', (d, i) => { return `clip${i}` })
.append('rect')
.attr('x', (d, i) => {
return `${clipRectData[i].getComputedTextLength()}`
})
.attr('height', (d, i) => {
return `${clipRectData[i].getBBox().height}`
})
.attr('width', (d, i) => {
return `${d.x2.baseVal.value-d.x1.baseVal.value}`
})
d3.selectAll('.tick>line').style('clip-path', (d, i) => {
return `url(#clip${i})`
})