Search code examples
cssd3.jsbackground-imagebubble-chart

Background image to bubble chart


I would like to add a background image for each circle of my bubble chart. I already read some solutions on different subject but it doesn't solve my problem. All the other style are correctly added but not the background-image style.

            scope.chart = function(rootData){

                var diameter = 900,
                    format = d3.format(",d"),
                    color = d3.scale.category20c();

                var bubble = d3.layout.pack()
                    .sort(null)
                    .size([diameter, diameter])
                    .value(function(d) { return (d.size); })
                    .padding(1.5);

                var svg = d3.select("body").append("svg")
                    .attr("width", diameter)
                    .attr("height", diameter)
                    .attr("id","svg")
                    .attr("class", "bubble");

                   var node = svg.selectAll(".node")
                    .data(bubble.nodes(classes(rootData))
                        .filter(function (d) {
                            return !d.children;
                        }))
                    .enter().append("g")
                    .attr("class", "node")
                    .attr("transform", function (d) {
                        return "translate(" + d.x + "," + d.y + ")";
                    });

                node.append("title")
                    .text(function(d) { return d.className + ": " + format(d.value); });

                node.append("circle")
                    .attr("r", function (d) {
                        return d.r;
                    })
                    .style("opacity", "0")
                    .style("fill", function (d) {
                            return "black"
                    })
                .style("background-image", function (d){
                       return "myImage2.png"
                });

                node.append("text")
                    .attr("dy", ".3em")
                    .style("text-anchor", "middle")
                    .text(function(d) { return d.className.substring(0, d.r / 3); })
                    .style("opacity", "0");


                node.on("click", click);

                    d3.selectAll("circle").style("fill", function (d) {
                            return "black"
                    });

                    d3.select(this).select("circle").style('fill', '#f2f40d');
                    d3.selectAll("circle").style("filter", null);
                    d3.select(this).select("circle").style("filter", "url(#f1)");

                }

                // Returns a flattened hierarchy containing all leaf nodes under the root.
                function classes(root) {
                    var classes = [];

                    function recurse(name, node) {
                        if (node.children) node.children.forEach(function (child) {
                            recurse(node.name, child);
                        });
                        else classes.push({
                            parameter1: name,
                            className: node.name,
                            size: node.size,
                        });
                    }

                    recurse(null, root);
                    return {children: classes};
                }
                d3.select(self.frameElement).style("height", diameter + "px");
            }

Edit : This is the code I tried but the image not appears.

/**
 * Create the bubble chart graph
 * @constructor
 */
d3DemoApp.directive('chart', [function($scope) {

        return {
            restrict: 'EA',
            transclude: true,
            scope: {
                parameter1: '=parameter1',
                paramete2: '=paramete2',
                paramete3: '=paramete3',
                paramete4: '=paramete4',
                paramete5: '=paramete5',
                chartData : '=',
                myFunction : '=myFunction'
            },

            link: function(scope) {

                scope.$watch('chartData', function(newValue) {
                    if (newValue){
                        scope.chart(newValue);
                    }
                });

                scope.chart = function(rootData){

                    d3.select('svg').remove(); // This delete the graph not wanted
                    d3.select('svg').remove(); // This delete the graph not wanted

                    var diameter = 900,
                        format = d3.format(",d"),
                        color = d3.scale.category20c();

                    var bubble = d3.layout.pack()
                        .sort(null)
                        .size([diameter, diameter])
                        .value(function(d) { return (d.paramete5+1); })
                        .padding(1.5);

                    var svg = d3.select("body").append("svg")
                        .attr("width", diameter)
                        .attr("height", diameter)
                        .attr("id","svg")
                        .attr("class", "bubble");

                        var node = svg.selectAll(".node")
                        .data(bubble.nodes(classes(rootData))
                            .filter(function (d) {
                                return !d.children;
                            }))
                        .enter().append("g")
                        .attr("class", "node")
                        .attr("transform", function (d) {
                            return "translate(" + d.x + "," + d.y + ")";
                        });

                    node.append("title")
                        .text(function(d) { return d.className + ": " + format(d.value); });


                    svg.append("defs")
                        .append("pattern")
                        .attr("id", "image")
                        .attr("height","100%")
                        .attr("width","100%")
                        .attr("x", "37%")
                        .attr("y","40%")
                        .append("image")
                        .attr("x", "0%")
                        .attr("y","0%")
                        .attr("viewBox", "0 0 200 200")
                        .attr("height","100")
                        .attr("width","100")
                        .attr("xlink:href", "linkImage");


                    node.append("circle")
                        .attr("r", function (d) {
                            return d.r;
                        })
                        .style("opacity", "0")
                        .style("fill", function (d) {
                                return "black"
                        })
                        .attr("fill", 'url("#image")');

                    node.append("text")
                        .attr("dy", ".3em")
                        .style("text-anchor", "middle")
                        .text(function(d) { return d.className.substring(0, d.r / 3); })
                        .style("opacity", "0");


                    node.on("click", click);
                    function click(d) {
                        scope.$apply(function () {
                            console.log("Call on apply");
                            scope.myFunction(); // Call is just correct once                                scope.parameter1 = d.parameter1;
                            scope.paramete3 = d.paramete3;
                            scope.paramete2 = d.title;
                            scope.paramete4 = d.paramete4;
                            scope.paramete5 = d.paramete5;
                        });

                        d3.selectAll("circle").style("fill", function (d) {
                                return "black"
                        });

                        d3.select(this).select("circle").style('fill', 'circle');
                        d3.selectAll("circle").style("filter", null);
                        d3.select(this).select("circle").style("filter", "url(#f1)");
                        var test = document.getElementById("svg");
                        function whatClicked(evt) {
                            if (evt.target.id == "svg"){
                                d3.selectAll("circle").style("fill", function (d) {
                                        return "black"
                                });
                            }
                            scope.myFunction();
                        }
                        test.addEventListener("click", whatClicked, true);
                    }

                    // Returns a flattened hierarchy containing all leaf nodes under the root.
                    function classes(root) {
                        var classes = [];

                        function recurse(name, node) {
                            if (node.children) node.children.forEach(function (child) {
                                recurse(node.name, child);
                            });
                            else classes.push({
                                parameter1: name,
                                className: node.name,
                                title: node.title,
                                value: node.paramete5,
                                paramete4: node.projectId,
                                parameter6: node.parameter7,
                                paramete5: node.paramete5,
                                paramete3: node.paramete3,
                                isLocked:node.isLocked
                            });
                        }

                        recurse(null, root);
                        return {children: classes};
                    }
                    d3.select(self.frameElement).style("height", diameter + "px");
                }


                if(typeof scope.chartData != "undefined"){
                    scope.drawChart(scope.chartData);
                }
            }
        };
    }]);

Solution

  • Here's the plunker: https://plnkr.co/edit/Kzr2a4HFG2yJxWfu90ri?p=preview

    If you want to show an image in the background of a svg element use defs:

     svg.append("defs")
            .append("pattern")
              .attr("id", "image")
              .attr("height","100%")
              .attr("width","100%")
              .attr("x", "37%")
              .attr("y","40%")
            .append("image")
              .attr("x", "0%")
              .attr("y","0%")
              .attr("viewBox", "0 0 200 200")
              .attr("height","100")
              .attr("width","100")
              .attr("xlink:href", "ImageLink");
    

    And give this reference to your element by url:

    .attr("fill", 'url("#image")');