Javascript d3.js带图像的强制布局

Javascript d3.js带图像的强制布局,javascript,d3.js,Javascript,D3.js,我试图在我自己的项目中使用这个例子。我试图概括要使用的代码块。我对代码做了一些修改,但现在它并没有生成示例中类似的图。您可以在JSFIDLE中看到我的尝试 var超级英雄=功能(选择器,w,h){ 这个.w=w; 这个,h=h; d3.选择(选择器).selectAll(“svg”).remove(); this.svg=d3.select(选择器).append(“svg:svg”) .attr('宽度',w) .attr('高度',h); this.svg.append(“svg:rect”

我试图在我自己的项目中使用这个例子。我试图概括要使用的代码块。我对代码做了一些修改,但现在它并没有生成示例中类似的图。您可以在JSFIDLE中看到我的尝试

var超级英雄=功能(选择器,w,h){
这个.w=w;
这个,h=h;
d3.选择(选择器).selectAll(“svg”).remove();
this.svg=d3.select(选择器).append(“svg:svg”)
.attr('宽度',w)
.attr('高度',h);
this.svg.append(“svg:rect”)
.style(“笔划”,“#999”)
.style(“填充”、“fff”)
.attr('宽度',w)
.attr('高度',h);
this.force=d3.layout.force()
.charge(函数(d){return d._children?-d.size/100:-40;})
.linkDistance(函数(d){返回d.target._子对象?80:25;})
.尺寸([h,w]);
};
//一些颜色变量
变量tcBlack=“#130C0E”;
//其余的VAR
var maxNodeSize=50,
x_=20,
y_=25;
/*
d3.json(“marvel.json”,函数(json){
//修路
var defs=this.svg.insert(“svg:defs”)
.数据([“结束]);
defs.enter().append(“svg:path”)
.attr(“d”,“M0,-5L10,0L0,5”);
这个.update();
});
*/
/**
*
*/
superheros.prototype.update=函数(json){
this.root=json;
this.root.fixed=true;
这个.root.x=w/2;
这个.root.y=h/4;
var nodes=this.flatte(this.root),
links=d3.layout.tree().links(节点);
//重新启动强制布局。
此.force.nodes(节点)
.链接(links)
.重力(0.05)
。收费(-1500)
.linkDistance(100)
.摩擦力(0.5)
.linkStrength(函数(l,i){return 1;})
.尺寸([w,h])
.on(“滴答”,滴答)
.start();
var path=this.svg.selectAll(“path.link”)
.data(链接,函数(d){返回d.target.id;});
path.enter().insert(“svg:path”)
.attr(“类”、“链接”)
//.attr(“标记结束”、“url(#结束)”)
.风格(“笔划”、“eee”);
//退出任何旧路径。
path.exit().remove();
//更新节点…
var node=this.svg.selectAll(“g.node”)
.data(节点,函数(d){返回d.id;});
//输入任何新节点。
var nodeEnter=node.enter().append(“svg:g”)
.attr(“类”、“节点”)
.attr(“transform”,函数(d){return“translate”(“+d.x+”,“+d.y+”)”);})
.on(“单击”,这是“单击”)
.call(this.force.drag);
//附加一个圆圈
追加(“svg:circle”)
.attr(“r”,函数(d){return Math.sqrt(d.size)/10 | | 4.5;})
.样式(“填充”、“eee”);
//附加图像
var images=nodeEnter.append(“svg:image”)
.attr(“xlink:href”,函数(d){return d.img;})
.attr(“x”,函数(d){return-25;})
.attr(“y”,函数(d){return-25;})
.attr(“高度”,50)
.attr(“宽度”,50);
//在鼠标上方使图像稍微增长,并在单击时添加文本详细信息
var setEvents=图像
//附加英雄文本
.on('点击',功能(d){
d3.选择(“h1”).html(d.hero);
d3.选择(“h2”).html(d.name);
d3.选择(“h3”).html(“带我到“+”);
})
.on('mouseenter',function(){
//选择当前上下文中的元素
d3.选择(本)
.transition()
.attr(“x”,函数(d){return-60;})
.attr(“y”,函数(d){return-60;})
.attr(“高度”,100)
.attr(“宽度”,100);
})
//倒退
.on('mouseleave',function(){
d3.选择(本)
.transition()
.attr(“x”,函数(d){return-25;})
.attr(“y”,函数(d){return-25;})
.attr(“高度”,50)
.attr(“宽度”,50);
});
//在节点旁边的翻滚上附加英雄名称
nodeEnter.append(“文本”)
.attr(“类”、“节点文本”)
.attr(“x”,x_浏览器)
.attr(“y”,y_浏览器+15)
.attr(“填充”,黑色)
.text(函数(d){return d.hero;});
//退出所有旧节点。
node.exit().remove();
//重新选择以进行更新。
path=this.svg.selectAll(“path.link”);
node=this.svg.selectAll(“g.node”);
函数tick(){
attr(“d”,函数(d){
变量dx=d.target.x-d.source.x,
dy=d.target.y-d.source.y,
dr=Math.sqrt(dx*dx+dy*dy);
返回“M”+d.source.x+”,“
+d.source.y
+“A”+dr+,”
+dr+“0,1”
+d.target.x+“,”
+d.target.y;
});
attr(“transform”,this.nodeTransform);
}
}
/**
*提供用于将节点保持在帧内的边界坐标
* http://bl.ocks.org/mbostock/1129492
*/
Superheros.prototype.nodeTransform=函数(d){
d、 x=Math.max(maxNodeSize,Math.min(w-(d.imgwidth/2 | | 16),d.x));
d、 y=Math.max(maxNodeSize,Math.min(h-(d.imgheight/2 | | | 16),d.y));
返回“translate”(“+d.x+”,“+d.y+”);
}
/**
*在单击时切换子项。
*/
superheros.prototype.click=函数(d){
如果(d.儿童){
d、 _children=d.children;
d、 children=null;
}否则{
d、 儿童=d.\U儿童;
d、 _children=null;
}
这个.update();
}
/**
*返回根目录下所有节点的列表。
*/
超级英雄.prototype.flatte=函数(根){
var节点=[];
var i=0;
函数递归(节点){
if(节点子节点)
node.children.forEach(递归);
如果(!node.id)
node.id=++i;
nodes.push(节点);
}
递归(根);
返回节点;
}
superheros.prototype.cleanup=函数(){
更新([]);
这个。强制。停止();
};
无功电流;
var createSuperheros=函数(json){
//删除上一朵花以保存备忘
    var SuperHeroes = function(selector, w, h) {
    this.w = w;
    this.h = h;

    d3.select(selector).selectAll("svg").remove();

    this.svg = d3.select(selector).append("svg:svg")
        .attr('width', w)
        .attr('height', h);

    this.svg.append("svg:rect")
        .style("stroke", "#999")
        .style("fill", "#fff")
        .attr('width', w)
        .attr('height', h);

    this.force = d3.layout.force()
        .charge(function(d) { return d._children ? -d.size / 100 : -40; })
        .linkDistance(function(d) { return d.target._children ? 80 : 25; })
        .size([h, w]);
};

// some colour variables
var tcBlack = "#130C0E";

// rest of vars
var maxNodeSize = 50,
    x_browser = 20,
    y_browser = 25;


/*
d3.json("marvel.json", function(json) {




    // Build the path
    var defs = this.svg.insert("svg:defs")
        .data(["end"]);


    defs.enter().append("svg:path")
        .attr("d", "M0,-5L10,0L0,5");

    this.update();
});
*/

/**
 *
 */
SuperHeroes.prototype.update = function(json) {
    this.root = json;
    this.root.fixed = true;
    this.root.x = w / 2;
    this.root.y = h / 4;

    var nodes = this.flatten(this.root),
        links = d3.layout.tree().links(nodes);

    // Restart the force layout.
    this.force.nodes(nodes)
        .links(links)
        .gravity(0.05)
        .charge(-1500)
        .linkDistance(100)
        .friction(0.5)
        .linkStrength(function(l, i) {return 1; })
        .size([w, h])
        .on("tick", tick)
        .start();

    var path = this.svg.selectAll("path.link")
        .data(links, function(d) { return d.target.id; });

    path.enter().insert("svg:path")
        .attr("class", "link")
        // .attr("marker-end", "url(#end)")
        .style("stroke", "#eee");


    // Exit any old paths.
    path.exit().remove();



    // Update the nodes…
    var node = this.svg.selectAll("g.node")
        .data(nodes, function(d) { return d.id; });


    // Enter any new nodes.
    var nodeEnter = node.enter().append("svg:g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
        .on("click", this.click)
        .call(this.force.drag);

    // Append a circle
    nodeEnter.append("svg:circle")
        .attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
        .style("fill", "#eee");


    // Append images
    var images = nodeEnter.append("svg:image")
        .attr("xlink:href",  function(d) { return d.img;})
        .attr("x", function(d) { return -25;})
        .attr("y", function(d) { return -25;})
        .attr("height", 50)
        .attr("width", 50);

    // make the image grow a little on mouse over and add the text details on click
    var setEvents = images
    // Append hero text
        .on( 'click', function (d) {
            d3.select("h1").html(d.hero);
            d3.select("h2").html(d.name);
            d3.select("h3").html ("Take me to " + "<a href='" + d.link + "' >"  + d.hero + " web page ⇢"+ "</a>" );
        })

        .on( 'mouseenter', function() {
            // select element in current context
            d3.select( this )
                .transition()
                .attr("x", function(d) { return -60;})
                .attr("y", function(d) { return -60;})
                .attr("height", 100)
                .attr("width", 100);
        })
        // set back
        .on( 'mouseleave', function() {
            d3.select( this )
                .transition()
                .attr("x", function(d) { return -25;})
                .attr("y", function(d) { return -25;})
                .attr("height", 50)
                .attr("width", 50);
        });

    // Append hero name on roll over next to the node as well
    nodeEnter.append("text")
        .attr("class", "nodetext")
        .attr("x", x_browser)
        .attr("y", y_browser +15)
        .attr("fill", tcBlack)
        .text(function(d) { return d.hero; });


    // Exit any old nodes.
    node.exit().remove();


    // Re-select for update.
    path = this.svg.selectAll("path.link");
    node = this.svg.selectAll("g.node");

    function tick() {


        path.attr("d", function(d) {

            var dx = d.target.x - d.source.x,
                dy = d.target.y - d.source.y,
                dr = Math.sqrt(dx * dx + dy * dy);
            return   "M" + d.source.x + ","
                + d.source.y
                + "A" + dr + ","
                + dr + " 0 0,1 "
                + d.target.x + ","
                + d.target.y;
        });
        node.attr("transform", this.nodeTransform);
    }
}


/**
 * Gives the coordinates of the border for keeping the nodes inside a frame
 * http://bl.ocks.org/mbostock/1129492
 */
SuperHeroes.prototype.nodeTransform = function(d) {
    d.x =  Math.max(maxNodeSize, Math.min(w - (d.imgwidth/2 || 16), d.x));
    d.y =  Math.max(maxNodeSize, Math.min(h - (d.imgheight/2 || 16), d.y));
    return "translate(" + d.x + "," + d.y + ")";
}

/**
 * Toggle children on click.
 */
SuperHeroes.prototype.click = function(d) {
    if (d.children) {
        d._children = d.children;
        d.children = null;
    } else {
        d.children = d._children;
        d._children = null;
    }

    this.update();
}


/**
 * Returns a list of all nodes under the root.
 */
SuperHeroes.prototype.flatten = function(root) {
    var nodes = [];
    var i = 0;

    function recurse(node) {
        if (node.children)
            node.children.forEach(recurse);
        if (!node.id)
            node.id = ++i;
        nodes.push(node);
    }

    recurse(root);
    return nodes;
}

SuperHeroes.prototype.cleanup = function() {
    this.update([]);
    this.force.stop();
};

 var currentSuperHereos;
    var createSuperHeroes = function(json) {
        // remove previous flower to save memory
        if (currentSuperHereos) currentSuperHereos.cleanup();
        // adapt layout size to the total number of elements
        var total = 5;
        w = parseInt(Math.sqrt(total) * 30, 10);
        h = parseInt(Math.sqrt(total) * 30, 10);

        if (h < 300) h = 300;
        if (w < 300) w = 300;
        // create a new SuperHeroes
        currentSuperHereos = new SuperHeroes("#visualization", w, h).update(json);

        var defs = this.svg.insert("svg:defs")
                .data(["end"]);


        defs.enter().append("svg:path")
                .attr("d", "M0,-5L10,0L0,5");
    };

    createSuperHeroes(JSON.parse('{"name":"MAlkara","img":"https://upload.wikimedia.org/wikipedia/commons/6/60/Google-Fit-Icon.png","children":[{"hero":"Kesan","name":"Keşan","img":"https://upload.wikimedia.org/wikipedia/commons/6/60/Google-Fit-Icon.png","additionalProperties":{}}],"additionalProperties":{}}'));
function tick() {
    path.attr("d", function(d) {
        var dx = d.target.x - d.source.x,
            dy = d.target.y - d.source.y,
            dr = Math.sqrt(dx * dx + dy * dy);
        return   "M" + d.source.x + ","
            + d.source.y
            + "A" + dr + ","
            + dr + " 0 0,1 "
            + d.target.x + ","
            + d.target.y;
    });
    node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
  path.enter().insert("svg:path")
    .attr("class", "link")    
    .style("stroke", "#eee")
    .attr("id",function(d,i){ return "linkId_"+i; });

   path.enter().append("g").attr("class", "linklabelholder")
     .append("text")
     .attr("class", "linklabel")
     .style("font-size", "13px")    
     .attr("text-anchor", "middle")
     .style("fill","#000")
     .append("textPath")
     .style('text-anchor', 'middle')
     .attr('startOffset', '50%')
     .attr("xlink:href",function(d,i) { return "#linkId_" + i;})
     .text(function(d) { 
         return "my text"; //Can be dynamic via d object 
     });