试图找到一种在 D3 中将图像放在圆圈内的方法。
img 已加载到 DOM 中,但我无法让它在圆圈内呈现。
要点是在顶部放置一张图片,因此圆圈背景颜色必须保持原样(颜色编码目的)。
我在这里做错了什么?
期望的输出:
我的代码:
function render(name) {
let markerCircles = svg.selectAll("circle")
.data([1, 2, 3, 4, 5])
.enter()
.append("circle")
.style("fill", "none")
.attr("stroke", "#ff97c4")
.style("stroke-width", "1.5px")
.attr("cy", fullSVGHeight / 2)
.attr("cx", markerCirclesScale(name) + 330)
.attr("r", 0)
markerCircles
.transition()
.duration(1000)
.attr("r", function(d) {
return d * 65;
});
let personCircles = svg.selectAll("a")
.data(data)
.enter()
.append("a")
.attr("id", function(d) {
console.log(d["Person Name"]);
if (d && d.length !== 0) {
return d["Person Name"].replace(/ |,|\./g, '_');
}
})
.style("opacity", 1)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
//Define defs
let defs = personCircles.append("defs");
defs.append('rect')
.attr('id', 'pic')
.attr('x', function(d){
return markerCirclesScale(name)
})
.attr('y', function(d){
return fullSVGHeight / 2;
})
.attr('width', 120)
.attr('height', 30)
.attr('rx', 10)
.style('fill', 'blue')
defs.append("clipPath")
.append("use")
.attr('xlink:href', '_')
.attr("z-index", 1000)
d3.timeout(function() {
personCircles
.append("use")
.attr('xlink:href', "_")
.append('image')
.attr('xlink:href', function(d){
return 'https://vignette.wikia.nocookie.net/ideas/images/8/82/Donald_Trump.png/revision/latest/scale-to-width-down/640?cb=20170512015233'})
.attr("clip-path", "url(#pic)")
.attr("width", 120)
.attr("height", 30)
.attr("y", fullSVGHeight / 2)
.attr("x", markerCirclesScale(name))
.attr("opacity", .8)
.append("circle")
.attr("cy", fullSVGHeight / 2)
.attr("cx", markerCirclesScale(name) + 330)
.attr("r", 20)
.append("title")
.text(function(d) {
return "Name: " + d["Person Name"] + ", " + "Time in the company: " + (+d["Period"] + " years");
});
simulation.restart().on("tick", ticked);
}, 2000)
最佳答案
D3 代码几乎没问题,但受限于 SVG 元素的层次结构。 好像应该是这样的顺序:
<a>
ID这里对于具体的图片展示任务不需要
let personCircles = svg.selectAll("a")
.data(data)
.enter()
.append("a")
.attr("id", function(d) {
console.log(d["Person Name"]);
if (d && d.length !== 0) {
return d["Person Name"].replace(/ |,|\./g, '_');
}
})
.style("opacity", 1)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
然后定义
<defs>
//Define defs
let defs = personCircles.append("defs");
然后是放置图片的第一个容器
<rect id = "RECT" / >
//ID 是必需的
defs.append('rect')
.attr('id', 'rect-ggg')
.attr('x', function(d){
return markerCirclesScale(name)
})
.attr('y', function(d){
return fullSVGHeight / 2;
})
.attr('width', 60)
.attr('height', 60)
.attr('rx', 40)
.style('fill', 'red')
容器附加了一个夹子来创建一个面具
<clipPath id = "the CLIP">
//这里也需要ID
defs.append("clipPath")
.attr('id', 'clip-ggg')
将掩码绑定(bind)到容器
<use the href = "# a RECT"> </use>
//容器的引用
.append("use")
.attr('href', function(d){
return "#rect-ggg";
})
<use>
据我了解,这需要向页面添加一个容器,因为浏览器不会呈现 DEFS 内容本身
<use href = "# RECT" > </ use>
//容器的引用
personCircles
.append("use")
.attr('href', function(d){
return "#rect-ggg";
})
最后添加照片
<image href clip-path = " url (#CLIP)" />
//引用掩码
personCircles.append('image')
.attr('href', function(d){
return 'https://vignette.wikia.nocookie.net/ideas/images/8/82/Donald_Trump.png/revision/latest/scale-to-width-down/640?cb=20170512015233'})
.attr("clip-path", function(d){
return "url(#clip-ggg)";
})
.attr("width", 60)
.attr("height", 60)
.attr('x', function(d){
return markerCirclesScale(name)
})
.attr('y', function(d){
return fullSVGHeight / 2 + 8;
})
circle
//这个圆圈不是必需的,我在我的布局中使用它来添加描边
//Define SVG width and height
let fullSVGHeight = 700;
let fullSVGWidth = 900;
//Define margins
// let margins = {
// top: 10,
// right: 50,
// bottom: 10,
// left: 10
// }
//Define chart width, height, x/y scale
// let chartHeight = fullSVGHeight - margins.top - margins.bottom;
// let chartWidth = fullSVGWidth - margins.left - margins.right;
//Define marker circles scale
let markerCirclesScale = d3.scalePoint()
.range([0, fullSVGWidth])
//Fetch data
d3.json("https://api.myjson.com/bins/7gjbe").then(data => {
// data.forEach(function(d){
// console.log("This is initial d.Period: ", +d.Period)
// return data.filter(function() {
// if (+d["Period"] === 0){
// return d["Period"] = 1;
// } else {
// return d.Period = Math.floor(+d["Period"]);
// }
// })});
console.log(data);
markerCirclesScale
.domain(data.map(function(d) {
return d["Person Name"];
}))
let svg = d3.select("body")
.append("svg")
.attr("width", fullSVGWidth)
.attr("height", fullSVGHeight)
.append("g")
.attr("transform", "translate(" + 0 + "," + 0 + ")");
data.forEach(function(d) {
return render(d["Person Name"])
});
function render(name) {
let markerCircles = svg.selectAll("circle")
.data([1, 2, 3, 4, 5])
.enter()
.append("circle")
.style("fill", "none")
.attr("stroke", "#ff97c4")
.style("stroke-width", "1.5px")
.attr("cy", fullSVGHeight / 2)
.attr("cx", markerCirclesScale(name) + 330)
.attr("r", 0)
markerCircles
.transition()
.duration(1000)
.attr("r", function(d) {
return d * 65;
});
let personCircles = svg.selectAll("a")
.data(data)
.enter()
.append("a")
.attr("id", function(d) {
console.log(d["Person Name"]);
if (d && d.length !== 0) {
return d["Person Name"].replace(/ |,|\./g, '_');
}
})
.style("opacity", 1)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
//Define defs
let defs = personCircles.append("defs");
defs.append('rect')
.attr('id', 'rect-ggg')
.attr('x', function(d){
return markerCirclesScale(name)
})
.attr('y', function(d){
return fullSVGHeight / 2;
})
.attr('width', 60)
.attr('height', 60)
.attr('rx', 40)
.style('fill', 'red')
defs.append("clipPath")
.attr('id', 'clip-ggg')
.append("use")
.attr('href', function(d){
return "#rect-ggg";
})
let simulation = d3.forceSimulation(data)
.force("charge", d3.forceCollide().radius(3))
.force('center', d3.forceCenter(fullSVGWidth / 2, fullSVGHeight / 2))
.force("radius", d3.forceRadial(function(d) {
return +d["Period"] * 60
}, fullSVGWidth / 2, fullSVGHeight / 2).strength(0.3))
.on("tick", ticked)
.velocityDecay(0.07)
.stop();
function ticked() {
personCircles
.attr("cx", function(d) { return d.x - 100; })
.attr("cy", function(d) { return d.y; });
}
d3.timeout(function() {
personCircles
.append("use")
.attr('href', function(d){
return "#rect-ggg";
})
personCircles.append('image')
.attr('href', function(d){
return 'https://vignette.wikia.nocookie.net/ideas/images/8/82/Donald_Trump.png/revision/latest/scale-to-width-down/640?cb=20170512015233'})
.attr("clip-path", function(d){
return "url(#clip-ggg)";
})
.attr("width", 60)
.attr("height", 60)
.attr('x', function(d){
return markerCirclesScale(name)
})
.attr('y', function(d){
return fullSVGHeight / 2 + 8;
})
simulation.restart().on("tick", ticked);
}, 2000)
function dragstarted(d) {
d.dragged = true;
simulation.alphaTarget(0.8).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
d3.timeout(function() {
d.dragged = false;
}, 1000)
}
}
}).catch(error => console.log(error));
body, body *{
top:0;
padding: 0;
margin: 0;
background-color: #80d6c7;
overflow: hidden;
font-family: Lucida Console, Monaco, monospace;
}
a {
background-color: transparent;
color: #679fa5;
text-decoration: none;
}
svg {
margin-top: 2% ;
margin-left: 29%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
关于javascript - 节点/圆顶部的 d3 图像不适用于 clipPath,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53655993/