我想使用d3向包含许多circle
元素的现有SVG中添加笑脸(或皱眉)。
到目前为止,通过将元素直接附加到SVG根目录,我已经能够实现这一目标。可行,但这只是因为它们的坐标恰好以正确的方式设置。
我想扩展它,以便能够在任意数量的圆圈中添加笑脸,无论它们位于何处。
我尝试过选择圈子并将其添加到圈子,但这是行不通的。
这是我到目前为止所取得的成就:
let svg = d3.select("#mySvg");
let appendedTo = svg;
//let appendedTo = svg.select(".mainCircle");
appendedTo.append("circle")
.attr("cx",13)
.attr("cy",15)
.attr("r",5);
appendedTo.append("circle")
.attr("cx",37)
.attr("cy",15)
.attr("r",5);
var arc = d3.svg.arc()
.innerRadius(10)
.outerRadius(11)
.startAngle(3*(Math.PI/2)) //converting from degs to radians
.endAngle(5 * (Math.PI/2)) //just radians
appendedTo.append("path")
.attr("d", arc)
.attr("transform", "translate(25,40)");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width = 50 height = 50 id="mySvg">
<circle class="mainCircle" cx=25 cy=25 r=25 fill="red"></circle>
</svg>
问题在于,圆圈在HTML页面上的位置发生了变化,笑脸的定位不正确。
您能给我一些指导,将笑脸“锚定”到圆形元素上吗?
编辑:
SVG示例:
<svg width = 500 height = 500 id="mySvg">
<circle class="mainCircle" cx=25 cy=25 r=25 fill="red"></circle>
<circle class="mainCircle" cx=125 cy=65 r=50 fill="red"></circle>
<circle class="mainCircle" cx=200 cy=12 r=10 fill="red"></circle>
<circle class="mainCircle" cx=210 cy=300 r=90 fill="red"></circle>
<circle class="mainCircle" cx=320 cy=25 r=5 fill="red"></circle>
<circle class="mainCircle" cx=400 cy=120 r=50 fill="red"></circle>
<circle class="mainCircle" cx=410 cy=230 r=25 fill="red"></circle>
</svg>
答案 0 :(得分:2)
我认为这里的一个好的解决方案是创建一个函数,您可以将圆的属性(cx
,cy
和r
)传递给该函数,从而创建基于表情的仅在这些值上。
例如,假设我们圈子的数据具有x
,y
和r
作为这些属性。我们可以创建一个名为makeSmileys
的函数,该函数绘制容器组中的圆圈和路径:
function makeSmileys(group, xPos, yPos, radius) {
//left eye
group.append("circle")
.attr("cx", xPos - radius / 3)
.attr("cy", yPos - radius / 3)
.attr("r", radius / 8)
.style("fill", "black");
//right eye
group.append("circle")
.attr("cx", xPos + radius / 3)
.attr("cy", yPos - radius / 3)
.attr("r", radius / 8)
.style("fill", "black");
arc.innerRadius(radius / 2)
.outerRadius(radius / 2.2);
//mouth
group.append("path")
.attr("d", arc)
.attr("transform", "translate(" + xPos + "," + yPos + ")");
}
如您所见,两只眼睛(圆圈)和嘴巴(路径)的位置仅基于参数。您可以按照自己的方式调整这些位置。
为使此功能正常工作,我们必须创建容器组,然后在相应的选择中调用它:
circlesGroup.each(function(d) {
d3.select(this).call(makeSmileys, d.x, d.y, d.r)
})
因为我使用的是selection.call
,所以第一个参数(即group
)就是选择本身。或者,如果您不想使用selection.call
,只需将函数作为普通的JavaScript函数调用,并将容器传递给它即可。
这是一个演示,带有10个随机生成的圆圈:
const svg = d3.select("svg");
const data = d3.range(10).map(function(d) {
return {
x: 50 + Math.random() * 500,
y: 50 + Math.random() * 300,
r: Math.random() * 50
}
});
const arc = d3.arc()
.startAngle(1 * (Math.PI / 2))
.endAngle(3 * (Math.PI / 2));
const circlesGroup = svg.selectAll(null)
.data(data)
.enter()
.append("g");
circlesGroup.each(function(d) {
d3.select(this).append("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", d => d.r)
.style("fill", "yellow")
.style("stroke", "black")
})
circlesGroup.each(function(d) {
d3.select(this).call(makeSmileys, d.x, d.y, d.r)
})
function makeSmileys(group, xPos, yPos, radius) {
group.append("circle")
.attr("cx", xPos - radius / 3)
.attr("cy", yPos - radius / 3)
.attr("r", radius / 8)
.style("fill", "black");
group.append("circle")
.attr("cx", xPos + radius / 3)
.attr("cy", yPos - radius / 3)
.attr("r", radius / 8)
.style("fill", "black");
arc.innerRadius(radius / 2)
.outerRadius(radius / 2.2);
group.append("path")
.attr("d", arc)
.attr("transform", "translate(" + xPos + "," + yPos + ")");
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="600" height="400"></svg>
如果您已有SVG(如您在已编辑的问题中明确指出的那样),则可以使用选择器选择所有圈子...
const circles = svg.selectAll("circle");
...然后获取它们的属性,最后调用该函数:
circles.each(function() {
const x = +d3.select(this).attr("cx");
const y = +d3.select(this).attr("cy");
const r = +d3.select(this).attr("r");
makeSmileys(x, y, r)
});
在这里注意一元加号,因为获取器返回这些属性的字符串。
这是演示:
const svg = d3.select("svg");
const arc = d3.arc()
.startAngle(1 * (Math.PI / 2))
.endAngle(3 * (Math.PI / 2));
const circles = svg.selectAll("circle");
circles.each(function() {
const x = +d3.select(this).attr("cx");
const y = +d3.select(this).attr("cy");
const r = +d3.select(this).attr("r");
makeSmileys(x, y, r)
})
function makeSmileys(xPos, yPos, radius) {
svg.append("circle")
.attr("cx", xPos - radius / 3)
.attr("cy", yPos - radius / 3)
.attr("r", radius / 8)
.style("fill", "black");
svg.append("circle")
.attr("cx", xPos + radius / 3)
.attr("cy", yPos - radius / 3)
.attr("r", radius / 8)
.style("fill", "black");
arc.innerRadius(radius / 2)
.outerRadius(radius / 2.2);
svg.append("path")
.attr("d", arc)
.attr("transform", "translate(" + xPos + "," + yPos + ")");
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="500" id="mySvg">
<circle class="mainCircle" cx=25 cy=25 r=25 fill="yellow"></circle>
<circle class="mainCircle" cx=125 cy=65 r=50 fill="yellow"></circle>
<circle class="mainCircle" cx=200 cy=12 r=10 fill="yellow"></circle>
<circle class="mainCircle" cx=210 cy=300 r=90 fill="yellow"></circle>
<circle class="mainCircle" cx=320 cy=25 r=5 fill="yellow"></circle>
<circle class="mainCircle" cx=400 cy=120 r=50 fill="yellow"></circle>
<circle class="mainCircle" cx=410 cy=230 r=25 fill="yellow"></circle>
</svg>
答案 1 :(得分:-2)
不要在SVG元素上使用唯一标识符,而应使用类似这样的类:
<svg width="50" height="50" class="face">
然后在D3中,您可以像这样引用此类的所有实例:
let svg = d3.selectAll(".face");