javascript - 节点/圆顶部的 d3 图像不适用于 clipPath

标签 javascript image d3.js svg

试图找到一种在 D3 中将图像放在圆圈内的方法。

img 已加载到 DOM 中,但我无法让它在圆圈内呈现。

要点是在顶部放置一张图片,因此圆圈背景颜色必须保持原样(颜色编码目的)。

我在这里做错了什么?

Codepen

期望的输出:

enter image description here

我的代码:

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/

相关文章:

javascript - dc.js:当计数为零时包括所有条

javascript - Mono Moonlight XAML 到 Javascript

angularjs - 如何向客户端 Nodejs 和 Angular 提供图像

android - Aquery图片进度条无法隐藏

css repeat-x 右侧

coffeescript - 如何使用 CoffeeScript 使用 `this` 和 `_this`(粗箭头)?

javascript - Amcharts - 一些标签中的 HTML 标签

javascript - 删除index.html GWT

javascript - (function() 在此特定代码段中的含义是什么?

javascript - d3 桑基图中的排序节点