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("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>
Теперь я звоню выше showGraph js function
каждый раз при событии клика, который принимает count
параметр
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
}
Теперь, когда я даю счет 10, SVG выглядит так:
<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>
Отлично работает ровно 10 кругов с class electron
с разными cx and cy
участки Но если я дам сначала 7 или что-то меньше 10, а затем 10, svg будет выглядеть так:
<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>
Графики ровно 10 кругов с class electron
но cx
а также cy
повторяется, поэтому они перекрываются. Но это не пересекается, если я даю счет 10 в первый раз. Это хорошо работает, если я даю большой счет, то маленький. Но не если маленький, то большой. Заранее спасибо за помощь.
1 ответ
Проблема в том, что вы никогда не обновляете существующие "электроны", когда переходите с 7 на 10. В вашем коде
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?
});
все после enter()
применяется только к новым элементам, добавленным в.
Это общая путаница; Я ответил на другой вопрос, подобный этому, ранее сегодня, поэтому я попытаюсь объяснить его очень четко здесь (и тогда каждый может просто сослаться на это объяснение в будущем!).
Методы создания цепочек - это большая часть D3, но он может сделать только так. Все хотят связать все вместе, но вы должны следить за тем, когда ваша цепочка разделяется на enter()
или же exit()
выбор и вернуться к основному выбору для обновления.
Общая процедура обновления обычно имеет четыре "цепочки" (каждая заканчивается ;
):
Цепочка выбора, которая выбирает элементы, обновляет данные и сохраняет выбор в переменной, например, вы можете вызвать ее
var elements
Цепочка входа, начинающаяся с
elements.enter().
(или любое другое имя переменной, которое вы использовали для сохранения цепочки выбора), добавление новых элементов и установка любых атрибутов или стилей, которые будут постоянными (т. е. не изменятся при обновлении)Выходная цепь, начиная с
elements.exit().
с переходами (при использовании) иremove()
Цепочка обновления, начинающаяся только с сохраненной переменной выбора, за которой следуют все методы для установки атрибутов или стилей, которые необходимо обновить; это также установит эти атрибуты в первый раз для элементов, которые вы только что создали
.enter()
Да, вы можете делать вещи по-другому, но только если вы четко понимаете, что происходит и почему вы переходите от этого паттерна.
Этот подход также позволяет избежать повторения в вашем коде, когда вы повторно выбираете свои электроны и повторно применяете данные, чтобы получить в exit()
выбор.
Таким образом, для вашей программы применение метода четырехуровневого обновления будет выглядеть так:
//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; });
Извините, что так долго кто-то отвечал на ваш вопрос; это довольно сложная программа, и, вероятно, отпугнула людей со всеми математическими функциями. В будущем вам не нужно включать ваш метод AJAX (при условии, что вы проверили, что он возвращает правильные значения), но это поможет включить пример данных, которые возвращает запрос AJAX. И, конечно, рабочий пример на JSFiddle или Tributary еще лучше!
Лучший,
--ABR