svg 的动态角度线性渐变
dynamically angle linear gradient of svg
我正在向圆形图中的每条路径动态添加线性渐变。我希望每个渐变将每个路径从中间分开。像这样:
我知道我可以使用 gradientTransform
旋转渐变,但旋转会根据路径在圆形图中的位置而有所不同。如何计算路径角度并相应地绘制线性渐变?我也尝试过操纵线性渐变的 x1、x2、y1 和 y2 坐标,但我不确定如何相应地操纵它们。
let data = {
name: "demo",
children: [{
"ID": "001",
"Games": "PS2",
"children": [{
"ID": "001-1",
"Games": "PS2",
}]
},
{
"ID": "002",
"Games": "PS2",
"children": [{
"ID": "002-2",
"Games": "PS2",
}]
},
{
"ID": "003",
"Games": "PS2",
"children": [{
"ID": "003-1",
"Games": "PS2",
}]
},
{
"ID": "004",
"Games": "PS2",
"children": [{
"ID": "004-1",
"Games": "PS2",
}]
},
{
"ID": "005",
"Games": "PS2",
"children": [{
"ID": "005-5",
"Games": "PS2",
}]
}
]
}
let width = 500;
let height = 500;
let radius = Math.min(width, height) / 2;
let color = d3.scaleOrdinal(d3.schemeCategory20b);
let g = d3.select('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
// Data strucure
let partition = d3.partition()
.size([2 * Math.PI, radius]);
// Find data root
let root = d3.hierarchy(data)
.sum(function(d) {
return !d.children || d.children.length === 0 ? 2 : 0
});
// Size arcs
partition(root);
let arc = d3.arc()
.startAngle(function(d) {
return d.x0
})
.endAngle(function(d) {
return d.x1
})
.innerRadius(function(d) {
return d.y0
})
.outerRadius(function(d) {
return d.y1
});
let svg = d3.select('svg')
// Put it all together
g.selectAll('path')
.data(root.descendants())
.enter().append('path')
.attr("stroke-width", "5")
.each((d, i, m) => {
let lg = svg.append("defs")
.append("linearGradient")
.attr("id", `gradient${d.data.ID}`)
.attr("gradientTransform", `rotate([=10=])`)
.attr("x1", "0%")
.attr("x2", "100%")
.attr("y1", "0%")
.attr("y2", "0%")
lg.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#188F6B")
lg.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#3BDBAB")
})
.style("fill", (d) => {
return `url(#gradient${d.data.ID})`
})
.attr("display", function(d) {
return d.depth ? null : "none";
})
.attr("d", arc)
.style('stroke', '#fff')
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
这是我的解决方案:我只使用一个渐变和 2 个路径。结果就是您需要的两个。我将 2 条路径分组到一个组中,这样我就可以根据需要多次重复使用它。
这将大大简化您的代码。请注意,我正在将样式和所有属性移动到组中,因为它们是相同的。你不需要重复自己。
由于组是圆的 1/5 这意味着组的展开角是 72º
我重复使用组 4 次旋转使用元素 172 度,272 度,372 度和 4 72度。
由于绘图以点 {x:0,y:0} 为中心,因此您无需添加旋转中心。
<svg width="500" height="500" viewBox="-250 -250 500 500">
<g id="theG" style="fill: url(#gradient); stroke: rgb(255, 255, 255);" stroke-width="5">
<path d="M97.96420871541218,134.8361657291579A166.66666666666666,166.66666666666666,0,0,1,-97.96420871541217,134.8361657291579L-48.982104357706085,67.41808286457895A83.33333333333333,83.33333333333333,0,0,0,48.98210435770609,67.41808286457895Z" ></path>
<path d="M146.9463130731183,202.25424859373686A250,250,0,0,1,-146.94631307311826,202.25424859373686L-97.96420871541217,134.8361657291579A166.66666666666666,166.66666666666666,0,0,0,97.96420871541218,134.8361657291579Z"></path>
</g>
<use xlink:href="#theG" transform="rotate(72)" />
<use xlink:href="#theG" transform="rotate(144)" />
<use xlink:href="#theG" transform="rotate(216)" />
<use xlink:href="#theG" transform="rotate(288)" />
<defs>
<linearGradient id="gradient" gradientTransform="rotate(0)" x1="0%" x2="100%" y1="0%" y2="0%">
<stop offset="50%" stop-color="#188F6B"></stop>
<stop offset="50%" stop-color="#3BDBAB"></stop>
</linearGradient>
</defs>
</svg>
我正在向圆形图中的每条路径动态添加线性渐变。我希望每个渐变将每个路径从中间分开。像这样:
我知道我可以使用 gradientTransform
旋转渐变,但旋转会根据路径在圆形图中的位置而有所不同。如何计算路径角度并相应地绘制线性渐变?我也尝试过操纵线性渐变的 x1、x2、y1 和 y2 坐标,但我不确定如何相应地操纵它们。
let data = {
name: "demo",
children: [{
"ID": "001",
"Games": "PS2",
"children": [{
"ID": "001-1",
"Games": "PS2",
}]
},
{
"ID": "002",
"Games": "PS2",
"children": [{
"ID": "002-2",
"Games": "PS2",
}]
},
{
"ID": "003",
"Games": "PS2",
"children": [{
"ID": "003-1",
"Games": "PS2",
}]
},
{
"ID": "004",
"Games": "PS2",
"children": [{
"ID": "004-1",
"Games": "PS2",
}]
},
{
"ID": "005",
"Games": "PS2",
"children": [{
"ID": "005-5",
"Games": "PS2",
}]
}
]
}
let width = 500;
let height = 500;
let radius = Math.min(width, height) / 2;
let color = d3.scaleOrdinal(d3.schemeCategory20b);
let g = d3.select('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
// Data strucure
let partition = d3.partition()
.size([2 * Math.PI, radius]);
// Find data root
let root = d3.hierarchy(data)
.sum(function(d) {
return !d.children || d.children.length === 0 ? 2 : 0
});
// Size arcs
partition(root);
let arc = d3.arc()
.startAngle(function(d) {
return d.x0
})
.endAngle(function(d) {
return d.x1
})
.innerRadius(function(d) {
return d.y0
})
.outerRadius(function(d) {
return d.y1
});
let svg = d3.select('svg')
// Put it all together
g.selectAll('path')
.data(root.descendants())
.enter().append('path')
.attr("stroke-width", "5")
.each((d, i, m) => {
let lg = svg.append("defs")
.append("linearGradient")
.attr("id", `gradient${d.data.ID}`)
.attr("gradientTransform", `rotate([=10=])`)
.attr("x1", "0%")
.attr("x2", "100%")
.attr("y1", "0%")
.attr("y2", "0%")
lg.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#188F6B")
lg.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#3BDBAB")
})
.style("fill", (d) => {
return `url(#gradient${d.data.ID})`
})
.attr("display", function(d) {
return d.depth ? null : "none";
})
.attr("d", arc)
.style('stroke', '#fff')
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
这是我的解决方案:我只使用一个渐变和 2 个路径。结果就是您需要的两个。我将 2 条路径分组到一个组中,这样我就可以根据需要多次重复使用它。
这将大大简化您的代码。请注意,我正在将样式和所有属性移动到组中,因为它们是相同的。你不需要重复自己。
由于组是圆的 1/5 这意味着组的展开角是 72º
我重复使用组 4 次旋转使用元素 172 度,272 度,372 度和 4 72度。
由于绘图以点 {x:0,y:0} 为中心,因此您无需添加旋转中心。
<svg width="500" height="500" viewBox="-250 -250 500 500">
<g id="theG" style="fill: url(#gradient); stroke: rgb(255, 255, 255);" stroke-width="5">
<path d="M97.96420871541218,134.8361657291579A166.66666666666666,166.66666666666666,0,0,1,-97.96420871541217,134.8361657291579L-48.982104357706085,67.41808286457895A83.33333333333333,83.33333333333333,0,0,0,48.98210435770609,67.41808286457895Z" ></path>
<path d="M146.9463130731183,202.25424859373686A250,250,0,0,1,-146.94631307311826,202.25424859373686L-97.96420871541217,134.8361657291579A166.66666666666666,166.66666666666666,0,0,0,97.96420871541218,134.8361657291579Z"></path>
</g>
<use xlink:href="#theG" transform="rotate(72)" />
<use xlink:href="#theG" transform="rotate(144)" />
<use xlink:href="#theG" transform="rotate(216)" />
<use xlink:href="#theG" transform="rotate(288)" />
<defs>
<linearGradient id="gradient" gradientTransform="rotate(0)" x1="0%" x2="100%" y1="0%" y2="0%">
<stop offset="50%" stop-color="#188F6B"></stop>
<stop offset="50%" stop-color="#3BDBAB"></stop>
</linearGradient>
</defs>
</svg>