У меня есть график рассеяния с D3, и я пытаюсь добавить круги к выбору на основе изменения данных. Я передаю выбор данных до двух функций: render
и update
. Функция render
представляет собой начальную визуализацию, а update
имеет методы enter()
и exit()
. Я могу легко добавить исходный набор данных и не получить круги больше в наборе данных для выхода. Я использую d.id
в качестве заполнителя d3.D3js exit() и обновление работает, не может войти()
Проблема: когда я пытаюсь добавить enter()
добавленные точки данных, ничего не происходит. Я проверил длину нового выбора данных, и он больше, чем предыдущий. В DOM меньший набор данных остается (circle
s, которые уже были там), но новые круги не входят, хотя набор данных изменился.
Я просмотрел множество руководств по объединению данных, и я думаю, что я соответствующим образом назвал методы enter()
и exit()
. Что дает?
Вот мой код:
var container = angular.element(document.querySelector('.chart-container'))[0];
var margin = {
top: container.clientHeight/12,
right: container.clientWidth/14,
bottom: container.clientHeight/10,
left: container.clientWidth/11
};
var w = container.clientWidth - margin.left - margin.right;
var h = container.clientHeight - margin.top - margin.bottom;
// ******** **************** ******** //
// ******** INITIAL RENDER ******** //
function render(input) {
console.log(Object.keys(input).length);
var xScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ctc"]; })])
.range([0, w])
.nice();
var yScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ttc"]; })])
.range([h, 0])
.nice();
var rScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["effective"]; })])
.range([2, 15]);
// *********** //
// SVG ELEMENT //
var svg = d3.select('.chart-container')
.append('svg')
.attr('class', 'scatter')
.attr('viewBox', '0, 0, ' + Math.round(w + margin.left + margin.right) + ', ' + Math.round(h + margin.top + margin.bottom))
.attr('preserveAspectRatio', 'xMinYMin')
// used to center element and make use of margins
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// add circles in group
var circles = svg.append('g')
.attr('class','circles')
.attr('clip-path','url(#chart-area)');
// add individual circles
var circle = circles.selectAll('circle')
.data(input, function(d) {return d.id;})
.enter()
.append('circle')
.attr('class', 'circle')
.attr('cx', function(d) { return xScale(d["ctc"]); })
.attr('cy', function(d) { return yScale(d["ttc"]); })
.attr('r', function(d) { return rScale(d["effective"]); })
.attr('fill', function(d, i) { return d["effective"]; })
.on('mouseover', function(d) {
tooltip.style('visibility', 'visible');
return tooltip.text(d["technology"]);
})
.on("mousemove", function(){ return tooltip.style("top",
(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");})
// append clip path
svg.append('clipPath')
.attr('id','chart-area')
.append('rect')
.attr('class', 'rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', w)
.attr('height', h);
};
// ******** **************** ******** //
// ******** UPDATE ******** //
function update(updateObject) {
var input = updateObject;
var xScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ctc"]; })])
.range([0, w])
.nice();
var yScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["ttc"]; })])
.range([h, 0])
.nice();
var rScale = d3.scale.linear()
.domain([0, d3.max(input, function(d) { return d["effective"]; })])
.range([2, 15]);
var svg = d3.select('svg')
.data(input)
.attr('viewBox', '0, 0, ' + Math.round(w + margin.left + margin.right) + ', ' + Math.round(h + margin.top + margin.bottom))
.attr('preserveAspectRatio', 'xMinYMin')
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// BIND TO DATA
var circles = d3.selectAll('circle')
.data(input, function(d) { return d.id; });
// Circles Enter
circles.enter()
.insert('svg:circle')
.attr('class', 'circle')
.attr('cx', function(d) { return xScale(d["ctc"]); })
.attr('cy', function(d) { return yScale(d["ttc"]); })
.attr('r', function(d) { return rScale(d["effective"]); });
/*
.on('mouseover', function(d) {
tooltip.style('visibility', 'visible');
return tooltip.text(d["technology"]);
})
.on("mousemove", function(){ return tooltip.style("top",
(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");})
*/
// UPDATE
circles.transition()
.duration(1000)
.attr('cx', function(d) { return xScale(d["ctc"]); })
.attr('cy', function(d) { return yScale(d["ttc"]); })
.attr('r', function(d) { return rScale(d["effective"]); });
// EXIT
circles.exit()
.transition()
.duration(500)
.attr('r', 0)
.style('opacity', 0)
.style('fill', 'gray')
.remove();
}
Update здесь является codepen для тестирования: http://codepen.io/himmel/pen/JdNJMM
использование 'enter()' кажется правильным, я думаю, вы могли бы создать скрипку/фрагмент или что-то для тестирования? – jhinzmann
Я создаю его сейчас, скоро обновится. – Himmel
Кстати, всегда полезно использовать 'd3.scale.sqrt()' для радиуса окружностей, потому что с 'd3.scale.linear()' площадь круга не пропорциональна value;) – jhinzmann