Javascript 为 svg 生成动态剪辑路径
Javascript to generate dynamic clip-path for svg
我正在使用如下所示的 svg 元素
<!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 class="vBoxRect" width="1280" height="720" fill="none" stroke="red"></rect>
<rect class="boundRect" x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<g class="yAxis">
<g class="yAxisLeft" fill="none" font-size="10" font-family="sans-serif">
<g class="tick" 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 class="tick" 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 class="tick" 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>
使用 javascript,我打算生成一个 svg
,它将在文本后显示每个 yAxis
网格线。例如
为了以编程方式生成它,我的方法是生成一个 clipPath
,其中 rect
从 x=text.x+text.width
开始,与 y,width
和 [=20] 相同=] 并将其应用于每个 line
.
这是我目前尝试的方法
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 class="vBoxRect" width="1280" height="720" fill="none" stroke="red"></rect>
<rect class="boundRect" x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<g class="yAxis">
<g class="yAxisLeft" fill="none" font-size="10" font-family="sans-serif">
<g class="tick" 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 class="tick" 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 class="tick" 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>
我不知道我做错了什么。 return 这不是我想要的。
此外,javascript
中是否存在内置方法 currentyl,它对 svg
个元素执行 union/combine/intersect/subtract
操作?
这对我有用
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 class="vBoxRect" width="1280" height="720" fill="none" stroke="red"></rect>
<rect class="boundRect" x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<g class="yAxis">
<g class="yAxisLeft" fill="none" font-size="10" font-family="sans-serif">
<g class="tick" 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 class="tick" 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 class="tick" 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})`
})
我正在使用如下所示的 svg 元素
<!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 class="vBoxRect" width="1280" height="720" fill="none" stroke="red"></rect>
<rect class="boundRect" x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<g class="yAxis">
<g class="yAxisLeft" fill="none" font-size="10" font-family="sans-serif">
<g class="tick" 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 class="tick" 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 class="tick" 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>
使用 javascript,我打算生成一个 svg
,它将在文本后显示每个 yAxis
网格线。例如
为了以编程方式生成它,我的方法是生成一个 clipPath
,其中 rect
从 x=text.x+text.width
开始,与 y,width
和 [=20] 相同=] 并将其应用于每个 line
.
这是我目前尝试的方法
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 class="vBoxRect" width="1280" height="720" fill="none" stroke="red"></rect>
<rect class="boundRect" x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<g class="yAxis">
<g class="yAxisLeft" fill="none" font-size="10" font-family="sans-serif">
<g class="tick" 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 class="tick" 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 class="tick" 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>
我不知道我做错了什么。 return 这不是我想要的。
此外,javascript
中是否存在内置方法 currentyl,它对 svg
个元素执行 union/combine/intersect/subtract
操作?
这对我有用
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 class="vBoxRect" width="1280" height="720" fill="none" stroke="red"></rect>
<rect class="boundRect" x="70" y="70" width="1160" height="600" fill="none" stroke="green"></rect>
<g class="bound" style="transform: translate(70px, 70px);">
<g class="yAxis">
<g class="yAxisLeft" fill="none" font-size="10" font-family="sans-serif">
<g class="tick" 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 class="tick" 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 class="tick" 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})`
})