d3.js圆绘图在第一次尝试加载后无法正常工作 [英] d3.js circle plotting does not working properly while trying to load after first time

查看:128
本文介绍了d3.js圆绘图在第一次尝试加载后无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的d3.js代码:

 < script& 


var width = 300,
height = 300,
margin = 20;
var x_centre = width / 2;
var y_centre = height / 2;
var nuclear_radius = 15;

var vis = d3.select(#chart_container)append(svg:svg)
.attr(width,width)
.attr高度,高度);

var radiuses = [1,2,3];

var multiplier =(d3.min([width,height]) - 2 * margin - nuclear_radius)/(d3.max(radiuses)* 2);

var shells = vis.selectAll(circle.shell)
.data(radiuses)
.enter()。append(circle)
。 attr(class,shell)
.attr(cx,x_centre)
.attr(cy,y_centre)
.attr ,i){
return(d * multiplier);
});

var nucleus = vis.selectAll('circle.nucleus')
.data(['nucleus'])
.enter b $ b .attr(class,nucleus)
.attr(cx,x_centre)
.attr(cy,y_centre)
.attr ,nuclear_radius);


function showGraph(de){
var electrons = de


var radius_counts = {};
for(var i = 0; i if(electrons [i] .distance in radius_counts){
radius_counts [electrons [i] .distance] + = 1;
} else {
radius_counts [electrons [i] .distance] = 1;
}
}

//计算每个电子的x和y坐标值
//。
var keep_count = {};
electrons.forEach(function(d){
var siblings = radius_counts [d.distance];
if(d.distance in keep_count){
keep_count [d.distance] + = 1;
} else {
keep_count [d.distance] = 1;
}
var angle =(360 / siblings)* keep_count [d.distance];
var hyp = d.distance * multiplier;
if(angle <= 90){
var use_angle =(90- angle)*(Math.PI / 180);
var opp = Math.sin(use_angle)* hyp;
var adj = Math.cos(use_angle)* hyp;
dx = x_centre + adj;
dy = y_centre - opp;
} else if(angle< = 180){
var use_angle =(180 - angle)*(Math.PI / 180);
var opp = Math.sin(use_angle)
var adj = Math.cos(use_angle)* hyp;
dx = x_centre + opp;
dy = y_centre + adj;
} else if(angle < {
var use_angle =(270 - angle)*(Math.PI / 180);
var opp = Math.sin(use_angle)* hyp;
var adj = Math.cos )* hyp;
d.x = x_centre - adj;
d.y = y_centre + opp;
} else {
var use_angle =(360 - angle)*(Math.PI / 180);
var opp = Math.sin(use_angle)* hyp;
var adj = Math.cos(use_angle)* hyp;
d.x = x_centre - opp;
d.y = y_centre - adj;
}

});

var electron_nodes = vis.selectAll('circle.electron')
.data(electrons)
.enter()。append(circle)
。 attr(class,electron)
.attr(cx,function(d){return dx;})
.attr(cy,function(d){return dy; }
.attr(r,7)
.on(mouseover,function(d){
//如何将电子拖到圆周?
});
var svgData = vis.selectAll(circle.electron)
.data(electrons);
svgData.exit()。remove();
}

< / script>

现在我正在调用上面的 showGraph js函数每次点击事件需要计数参数

  function add_py ()
{
var count = $(#count).val();
$ .ajax({
type:get,
url:abc.py,
data:{'count':count},
datatype :script,
async:false,
success:function(response){
var data = JSON.parse(response);
// alert $ b showGraph(data);
},//成功关闭
错误:function(xhr,err)
{
alert(错误连接到服务器,请联系系统管理员。);
}
})// ajax closed
}

现在当我给数10,SVG是这样:

 < svg width =300height = 300> 
< circle class =shellcx =150cy =150r =40.833333333333336>
< circle class =shellcx =150cy =150r =81.66666666666667>
< circle class =shellcx =150cy =150r =122.5>
< circle class =nucleuscx =150cy =150r =15>
< circle class =electroncx =231.66666666666669cy =150r =7>
< circle class =electroncx =256.08811196359375cy =211.25r =7>
< circle class =electroncx =43.91188803640625cy =211.25r =7>
< circle class =electroncx =185.36270398786456cy =170.41666666666669r =7>
< circle class =electroncx =114.63729601213541cy =170.41666666666666r =7>
< circle class =electroncx =150cy =231.66666666666669r =7>
< circle class =electroncx =150cy =27.5r =7>
< circle class =electroncx =150cy =109.16666666666666r =7>
< circle class =electroncx =68.33333333333333cy =150r =7>
< circle class =electroncx =150cy =68.33333333333333r =7>
< / svg>

class electron 与不同的 cx和cy 情节。但是如果我给第一次计数7或者小于10然后10,则svg是:

 < svg width = 300height =300> 
< circle class =shellcx =150cy =150r =40.833333333333336>
< circle class =shellcx =150cy =150r =81.66666666666667>
< circle class =shellcx =150cy =150r =122.5>
< circle class =nucleuscx =150cy =150r =15>
< circle class =electroncx =150cy =68.33333333333333r =7>
< circle class =electroncx =150cy =272.5r =7>
< circle class =electroncx =150cy =27.5r =7>
< circle class =electroncx =150cy =190.83333333333334r =7>
< circle class =electroncx =150cy =109.16666666666666r =7>
< circle class =electroncx =150cy =231.66666666666669r =7>
< circle class =electroncx =150cy =27.5r =7>
< circle class =electroncx =150cy =109.16666666666666r =7>
< circle class =electroncx =68.33333333333333cy =150r =7>
< circle class =electroncx =150cy =68.33333333333333r =7>
< / svg>

class electron 绘制10个圆 cx cy 重复,因此它们重叠。但它不重叠,如果我给数10第一次。如果我给一个大计数然后小工作正常。但不是如果小,那么大。感谢您提前帮助我。

解决方案

问题是当你从7到10 。

  var electron_nodes = vis.selectAll('circle.electron')
.data
.enter()。append(circle)
.attr(class,electron)
.attr(cx,function(d){return dx;} )
.attr(cy,function(d){return dy;})
.attr(r,7)
.on {
//如何拖动电子在圆周围?
}); enter()后的所有内容仅适用于以下内容:



添加了新元素。



这是一个常见的混乱;我今天早些时候回答了另一个问题,所以我在这里尝试解释一下,然后每个人都可以链接到这个解释!



链接方法是D3的一个重要部分,但它只能做这么多。每个人都想链接一起,但你必须跟踪你的链分成 enter() exit()选择,并返回主要选择更新。



一般更新程序通常会有四个连锁(每个都以; ):




  • 选择链,用于选择元素并更新数据 c>


  • 将 (或用于保存选择链的任何变量名称)开始

    输入链,输入


  • 退出链

    strong>,从 elements.exit()。开始,使用转换(如果使用)和 remove() p>

  • 更新链仅从保存的选择变量开始,随后是所有需要设置属性或样式的方法更新;这也将首次为您刚刚使用 .enter()


创建的元素设置这些属性。

是的,你可以做不同的事情,但只有当你清楚地了解发生了什么,以及你为什么要从这种模式改变。



这种方法还避免了在代码中的重复,其中重新选择电子并重新应用数据以获得 exit()选择。



所以对于你的程序,4链更新方法的应用如下:

  // chain 1:select 
var electron_nodes = vis.selectAll('circle.electron')
.data(electrons);

// chain 2:输入
electron_nodes.enter()。append(circle)
.attr(class,electron)
。 on(mouseover,function(d){
//虽然这个函数使用事件发生时的数据,
//函数的实际定义从不改变,
//所以你只需要在创建节点时附加一次。
})
.attr(r,7);

// chain 3:exit
electron_nodes.exit()。remove();

// chain 4:update
electron_nodes.attr(cx,function(d){return dx;})
.attr(cy,function ){return dy;});对不起,花了这么长时间,有人回答你的问题;它是一个相当复杂的程序,并可能吓唬人们所有的数学功能。对于将来,您不需要包括您的AJAX方法(假设您已检查它返回正确的值),但它将有助于包括AJAX请求返回的数据的示例。当然,关于JSFiddle或支流的工作示例更好!



最好,

--ABR


This is my d3.js piece of code :

<script>


var width = 300,
height = 300,
margin = 20;
var x_centre = width/2;
var y_centre = height/2;
var nuclear_radius = 15;

var vis = d3.select("#chart_container").append("svg:svg")
.attr("width", width)
.attr("height", height);

var radiuses = [1,2,3];

var multiplier = (d3.min([width, height]) - 2*margin - nuclear_radius) / (d3.max(radiuses) * 2);

var shells = vis.selectAll("circle.shell")
 .data(radiuses)
 .enter().append("circle")
 .attr("class", "shell")
 .attr("cx", x_centre)
 .attr("cy", y_centre)
 .attr("r", function(d, i) { 
     return (d * multiplier);
  });

var nucleus = vis.selectAll('circle.nucleus')
.data(['nucleus'])
.enter().append("circle")
.attr("class", "nucleus")
.attr("cx", x_centre)
.attr("cy", y_centre)
.attr("r", nuclear_radius);


function  showGraph(de)  {
var electrons = de


var radius_counts = {};
for (var i = 0; i < electrons.length; i++) { 
if (electrons[i].distance in radius_counts) { 
     radius_counts[electrons[i].distance] += 1;
} else { 
     radius_counts[electrons[i].distance] = 1;
} 
}

// Calculate the x- and y-coordinate values 
// for each electron.
var keep_count = {};
electrons.forEach(function(d) { 
var siblings = radius_counts[d.distance];
if (d.distance in keep_count) { 
  keep_count[d.distance] += 1;    
} else { 
    keep_count[d.distance] = 1;
}
var angle = (360/siblings) * keep_count[d.distance];
var hyp = d.distance * multiplier;  
if (angle <= 90) {
  var use_angle = (90 - angle) * (Math.PI/180);
  var opp = Math.sin(use_angle) * hyp;
  var adj = Math.cos(use_angle) * hyp;
    d.x = x_centre + adj;
    d.y = y_centre - opp;
}    else if (angle <= 180) { 
        var use_angle = (180 - angle) * (Math.PI/180);
      var opp = Math.sin(use_angle) * hyp;
      var adj = Math.cos(use_angle) * hyp;
        d.x = x_centre + opp;
        d.y = y_centre + adj;    
    } else if (angle <= 270) { 
    var use_angle = (270 - angle) * (Math.PI/180);
  var opp = Math.sin(use_angle) * hyp;
  var adj = Math.cos(use_angle) * hyp;
    d.x = x_centre - adj;
    d.y = y_centre + opp;    
} else { 
    var use_angle = (360 - angle) * (Math.PI/180);    
  var opp = Math.sin(use_angle) * hyp;
  var adj = Math.cos(use_angle) * hyp;
    d.x = x_centre - opp;
    d.y = y_centre - adj;
}

});

var electron_nodes = vis.selectAll('circle.electron')
.data(electrons)
.enter().append("circle")
.attr("class", "electron")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 7)
.on("mouseover", function(d) { 
   // how to drag the electron around the circle?
});
var svgData = vis.selectAll("circle.electron")
    .data(electrons);   
svgData.exit().remove();       
}

</script> 

Now i am calling the above showGraph js function every time on click event which takes the count parameter

function add_py()
{
 var count = $( "#count" ).val();
    $.ajax({
        type: "get",
        url: "abc.py",
        data: {'count': count},
        datatype:"script",
        async: false,
        success: function(response) {
        var data= JSON.parse(response);
        //alert(response)
        showGraph(data);
        }, // success closed
        error:function(xhr,err)
        {
            alert("Error connecting to server, please contact system administator.");
        }
    })//ajax closed
}

Now when I give count 10 , the SVG is like this :

<svg width="300" height="300">
    <circle class="shell" cx="150" cy="150" r="40.833333333333336">
    <circle class="shell" cx="150" cy="150" r="81.66666666666667">
    <circle class="shell" cx="150" cy="150" r="122.5">
    <circle class="nucleus" cx="150" cy="150" r="15">
    <circle class="electron" cx="231.66666666666669" cy="150" r="7">
    <circle class="electron" cx="256.08811196359375" cy="211.25" r="7">
    <circle class="electron" cx="43.91188803640625" cy="211.25" r="7">
    <circle class="electron" cx="185.36270398786456" cy="170.41666666666669" r="7">
    <circle class="electron" cx="114.63729601213541" cy="170.41666666666666" r="7">
    <circle class="electron" cx="150" cy="231.66666666666669" r="7">
    <circle class="electron" cx="150" cy="27.5" r="7">
    <circle class="electron" cx="150" cy="109.16666666666666" r="7">
    <circle class="electron" cx="68.33333333333333" cy="150" r="7">
    <circle class="electron" cx="150" cy="68.33333333333333" r="7">
</svg>

Works fine exactly 10 circles with class electron with different cx and cy plots . But if i give first count 7 or anything less then 10 then 10 , the svg is like :

<svg width="300" height="300">
    <circle class="shell" cx="150" cy="150" r="40.833333333333336">
    <circle class="shell" cx="150" cy="150" r="81.66666666666667">
    <circle class="shell" cx="150" cy="150" r="122.5">
    <circle class="nucleus" cx="150" cy="150" r="15">
    <circle class="electron" cx="150" cy="68.33333333333333" r="7">
    <circle class="electron" cx="150" cy="272.5" r="7">
    <circle class="electron" cx="150" cy="27.5" r="7">
    <circle class="electron" cx="150" cy="190.83333333333334" r="7">
    <circle class="electron" cx="150" cy="109.16666666666666" r="7">
    <circle class="electron" cx="150" cy="231.66666666666669" r="7">
    <circle class="electron" cx="150" cy="27.5" r="7">
    <circle class="electron" cx="150" cy="109.16666666666666" r="7">
    <circle class="electron" cx="68.33333333333333" cy="150" r="7">
    <circle class="electron" cx="150" cy="68.33333333333333" r="7">
</svg>

Plots exactly 10 circles with class electron but the cx and cy repeats so they overlap . But it does not overlap if I give count 10 first time .It works fine if i give a big count then small. But not if small then big. Thanks in advance for helping me.

解决方案

The problem is you are never updating existing "electrons" when you go from 7 to 10. In your code

var electron_nodes = vis.selectAll('circle.electron')
.data(electrons)
.enter().append("circle")
.attr("class", "electron")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 7)
.on("mouseover", function(d) { 
   // how to drag the electron around the circle?
});

everything after enter() only applies to new elements added in.

It's a common confusion; I answered another question like this earlier today, so I'm going to try to explain it really clearly here (and then everyone can just link to this explanation in future!).

Chaining methods is a great part of D3, but it can only do so much. Everyone wants to chain everything together, but you have to keep track of when your chain separates out into an enter() or exit() selection, and go back to the main selection for updating.

The general update routine will normally have four "chains" (each ended with a ;):

  • A Select Chain, that selects the elements and updates the data and saves the selection in a variable, for example you could call it var elements

  • An Enter Chain, starting with elements.enter(). (or whatever variable name you used to save the Select Chain), appending the new elements and setting any attributes or styles that are going to be constant (i.e., won't change on update)

  • An Exit Chain, starting with elements.exit()., with transitions (if using) and remove()

  • An Update Chain, starting just with your saved selection variable, followed by all the methods to set the attributes or styles that need to be updated; this will also set these attributes for the first time on the elements you just created with .enter()

Yes, you can do things differently, but only if you clearly understand what is happening and why you are changing from this pattern.

This approach also avoids the repetition in your code, where you re-select your electrons and re-apply the data to get at the exit() selection.

So for your program, the application of the 4-chain update method would look like this:

//chain 1: select
var electron_nodes = vis.selectAll('circle.electron')
      .data(electrons); 

//chain 2: enter
electron_nodes.enter().append("circle")
  .attr("class", "electron")
  .on("mouseover", function(d) { 
   // Although this function uses data at the time the event happens, 
   // the actual definition of the function never changes,
   // so you only need to attach it once when you create the node.
  })
  .attr("r", 7); 

//chain 3: exit
electron_nodes.exit().remove(); 

//chain 4: update
electron_nodes.attr("cx", function(d) { return d.x; })
  .attr("cy", function(d) { return d.y; });

Sorry it took this long for someone to answer your question; it's a rather complicated program, and probably scared people off with all the math functions. For future, you don't need to include your AJAX method (assuming you've checked that it's returning the correct values), but it would help to include an example of the data that the AJAX request returns. And of course, a working example on JSFiddle or Tributary is even better!

Best,
--ABR

这篇关于d3.js圆绘图在第一次尝试加载后无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆