[英]d3 image on top of node / circle doesn't work with clipPath
試圖在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
<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')
將蒙版綁定到容器
<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 dx - 100; }) .attr("cy", function(d) { return dy; }); } 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 = dx; d.fy = dy; } 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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.