D3: combine circles and images

后端 未结 1 1358
Happy的楠姐
Happy的楠姐 2021-01-24 08:15

I have function to generate circle and images

        node.append(\"circle\")
        .attr(\"r\", function(d) { return d.weight * 2+ 12; })
        .attr(\"clas         


        
相关标签:
1条回答
  • 2021-01-24 09:08

    You can use clip-path property to implement this as suggested by Brad.

    node.append("circle")
      .attr("r", function(d) {
        d.radius = d.weight * 2 + 12;
        return d.radius;
      })
      .attr("class", "logo")  
      .style("fill", "transparent")
      .style("stroke", "black")
      .style("stroke-width", 0.25)
      .on("mouseover", function() {
        d3.select(this)
          .style("fill", "url(#/images/fake/FakeTree/100331934)");
      })
      .on("mouseout", function() {
        d3.select(this)
          .style("fill", "transparent");
      });
    
    node.append("clipPath")
      .attr('id', function(d, i) {
        return "clip" + i
      })
      .append("circle")
      .attr("class", "clip-path")
      .attr("r", function(d) {
        return d.radius;
      })
      .style("fill", function(d) {
        return color(1 / d.rating);
      });
    
    node.append("svg:image")
      .attr("class", "circle")
      .attr("xlink:href", d => d.url)
      .attr("clip-path", function(d, i) {
        return "url(#clip" + i + ")"
      })
      .attr("x", function(d) {
        return -d.radius;
      })
      .attr("y", function(d) {
        return -d.radius;
      })
      .attr("width", function(d) {
        return d.radius * 2;
      })
      .attr("height", function(d) {
        return d.radius * 2;
      });
    

    var graph = {
      "nodes": [{
          "name": "1",
          "rating": 90,
          "id": 2951,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.pngo"
        }, {
          "name": "2",
          "rating": 80,
          "id": 654654,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "3",
          "rating": 80,
          "id": 6546544,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.pngo"
        }, {
          "name": "4",
          "rating": 1,
          "id": 68987978,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "5",
          "rating": 1,
          "id": 9878933,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "6",
          "rating": 1,
          "id": 6161,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "7",
          "rating": 1,
          "id": 64654,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "8",
          "rating": 20,
          "id": 354654,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "9",
          "rating": 50,
          "id": 8494,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "10",
          "rating": 1,
          "id": 6846874,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "11",
          "rating": 1,
          "id": 5487,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "12",
          "rating": 80,
          "id": "parfum_kenzo",
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "13",
          "rating": 1,
          "id": 65465465,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "14",
          "rating": 90,
          "id": "jungle_de_kenzo",
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "15",
          "rating": 20,
          "id": 313514,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "16",
          "rating": 40,
          "id": 36543614,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "17",
          "rating": 100,
          "id": "Yann_YA645",
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "18",
          "rating": 1,
          "id": 97413,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.png"
        }, {
          "name": "19",
          "rating": 1,
          "id": 97414,
          "url": "http://a4.mzstatic.com/us/r30/Purple71/v4/67/24/35/672435a3-3f19-4a13-21e6-057a8e5a3ca7/icon175x175.pngg"
        },
    
    
    
      ],
      "links": [{
          "source": 6,
          "target": 5,
          "value": 6,
          "label": "publishedOn"
        }, {
          "source": 8,
          "target": 5,
          "value": 6,
          "label": "publishedOn"
        }, {
          "source": 7,
          "target": 1,
          "value": 4,
          "label": "containsKeyword"
        }, {
          "source": 8,
          "target": 10,
          "value": 3,
          "label": "containsKeyword"
        }, {
          "source": 7,
          "target": 14,
          "value": 4,
          "label": "publishedBy"
        }, {
          "source": 8,
          "target": 15,
          "value": 6,
          "label": "publishedBy"
        }, {
          "source": 9,
          "target": 1,
          "value": 6,
          "label": "depicts"
        }, {
          "source": 10,
          "target": 1,
          "value": 6,
          "label": "depicts"
        }, {
          "source": 16,
          "target": 1,
          "value": 6,
          "label": "manageWebsite"
        }, {
          "source": 16,
          "target": 2,
          "value": 5,
          "label": "manageWebsite"
        }, {
          "source": 16,
          "target": 3,
          "value": 6,
          "label": "manageWebsite"
        },
    
    
      ]
    }
    
    //seting size and position
    var margin = {
      top: -5,
      right: -5,
      bottom: -5,
      left: -5
    };
    var width = 1000 - margin.left - margin.right,
      height = 400 - margin.top - margin.bottom;
    
    //give out random color for circle (currently disable)
    var color = d3.scale.category20();
    
    //the Link porperty
    var force = d3.layout.force()
      .charge(-200)
      .linkDistance(150)
      .size([width + margin.left + margin.right, height + margin.top + margin.bottom]);
    
    //interactive
    var zoom = d3.behavior.zoom()
      .scaleExtent([1, 10])
      .on("zoom", zoomed);
    
    var drag = d3.behavior.drag()
      .origin(function(d) {
        return d;
      })
      .on("dragstart", dragstarted)
      .on("drag", dragged)
      .on("dragend", dragended);
    
    //the main body
    var svg = d3.select("#map").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
      .call(zoom)
    
    var rect = svg.append("rect")
      .attr("width", width)
      .attr("height", height)
      .style("fill", "none")
      .style("pointer-events", "all");
    
    
    //fake data - should have some score and the peoplo s name1
    var x = {
      name: 'test',
      Id: '9999',
      score: '100'
    };
    
    //var z = "<b>"+x.Id+"</b>""<b>"+x.name+"</b>""<b>"+x.score+"</b>";
    
    var tooltip = d3.select("body")
      .append("div")
      .attr("class", "tooltip")
      .style("position", "absolute")
      .style("z-index", "9999")
      .style("visibility", "hidden")
      //.html(API); should get data from api
      .html("<b>Name : " + x.name + "</b>" + "<p>Id :" + x.Id + "</p>" + "<p>Score :" + x.score + "</p>");
    //.html(function(d) { return d.name});
    
    
    var container = svg.append("g");
    
    //d3.json('http://blt909.free.fr/wd/map2.json', function(error, graph) {
    
    force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();
    
    var link = container.append("g")
      .attr("class", "links")
      .selectAll(".link")
      .data(graph.links)
      .enter().append("line")
      .attr("class", "link")
      .style("stroke-width", function(d) {
        return Math.sqrt(d.value);
      });
    
    var node = container.append("g")
      .attr("class", "nodes")
      .selectAll(".node")
      .data(graph.nodes)
      .enter().append("g")
      .attr("class", "node")
      .attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      })
      .call(drag);
    
    node.append("circle")
      .attr("r", function(d) {
        d.radius = d.weight * 2 + 12;
        return d.radius;
      })
      .attr("class", "logo")  
      .style("fill", "transparent")
      .style("stroke", "black")
      .style("stroke-width", 0.25);
    
    node.append("clipPath")
      .attr('id', function(d, i) {
        return "clip" + i
      })
      .append("circle")
      .attr("class", "clip-path")
      .attr("r", function(d) {
        return d.radius;
      })
      .style("fill", function(d) {
        return color(1 / d.rating);
      });
    
    node.append("svg:image")
      .attr("class", "circle")
      .attr("xlink:href", d => d.url)
      .attr("clip-path", function(d, i) {
        return "url(#clip" + i + ")"
      })
      .attr("x", function(d) {
        return -d.radius;
      })
      .attr("y", function(d) {
        return -d.radius;
      })
      .attr("width", function(d) {
        return d.radius * 2;
      })
      .attr("height", function(d) {
        return d.radius * 2;
      });
    
    
    node.append("text")
      .attr("x", function(d) {
        return d.weight * 2 - 35;
      })
      .attr("y", height / 15 - 38)
      .style("opacity", "1")
      .html(function(d) {
        return d.name
      });
    
    
    force.on("tick", function() {
      link.attr("x1", function(d) {
          return d.source.x;
        })
        .attr("y1", function(d) {
          return d.source.y;
        })
        .attr("x2", function(d) {
          return d.target.x;
        })
        .attr("y2", function(d) {
          return d.target.y;
        });
    
      node.attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
      });
    });
    
    var linkedByIndex = {};
    graph.links.forEach(function(d) {
      linkedByIndex[d.source.index + "," + d.target.index] = 1;
    });
    
    function isConnected(a, b) {
      return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index];
    }
    
    //Show tooltip box
    node.on("mouseover", function(d) {
    
      node.classed("node-active", function(o) {
        thisOpacity = isConnected(d, o) ? true : false;
        this.setAttribute('fill-opacity', thisOpacity);
        return thisOpacity;
      });
    
      link.classed("link-active", function(o) {
        return o.source === d || o.target === d ? true : false;
      });
    
      d3.select(this).classed("node-active", true);
      
      tooltip.style("visibility", "visible")
      tooltip.style("diplay", "block")
        .style('top', d3.event.pageY - 6 + 'px')
        .style('left', d3.event.pageX + 10 + 'px')
    
    })
    
    //hide tooltip box
    .on("mouseout", function(d) {
    
      node.classed("node-active", false);
      link.classed("link-active", false);
      
      tooltip.style("visibility", "hidden")
    });
    
    // On Click, we want to add data to the array and chart
    svg.on("click", function() {
      var coords = d3.mouse(this);
    
      // Normally we go from data to pixels, but here we're doing pixels to data
      var newData = {
        x: Math.round(xScale.invert(coords[0])), // Takes the pixel number to convert to number
        y: Math.round(yScale.invert(coords[1]))
      };
    
      dataset.push(newData); // Push data to our array
    
      svg.selectAll("circle") // For new circle, go through the update process
        .data(dataset)
        .enter()
        .append("circle")
        .attr(circleAttrs) // Get attributes from circleAttrs var
        .on("mouseover", handleMouseOver)
        .on("mouseout", handleMouseOut);
    })
    
    
    function dottype(d) {
      d.x = +d.x;
      d.y = +d.y;
      return d;
    }
    
    function zoomed() {
      container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
    }
    
    function dragstarted(d) {
      d3.event.sourceEvent.stopPropagation();
    
      d3.select(this).classed("dragging", true);
      force.start();
    }
    
    function dragged(d) {
    
      d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
    
    }
    
    function dragended(d) {
    
      d3.select(this).classed("dragging", false);
    }
    .node {
      font: 10px sans-serif;
    }
    .node-active {
      stroke: #555;
      stroke-width: 1.5px;
    }
    .link {
      stroke: #555;
      stroke-opacity: .3;
    }
    .link-active {
      stroke-opacity: 1;
    }
    .overlay {
      fill: none;
      pointer-events: all;
    }
    #map {
      border: 2px #555;
      width: 1100px;
      height: 400px;
    }
    div.tooltip {
      position: absolute;
      padding: 2px;
      background: white;
      border-radius: 25px;
      padding: 20px;
      border: 2px solid steelblue;
      opacity: 1 !important;
    }
    .MakeItround {
      border-radius: 50%;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <body>
      <div id="map"></div>
    </body>

    0 讨论(0)
提交回复
热议问题