Возникли проблемы с шаблоном обновления D3v4 с 3 уровнями вложенных данных. - PullRequest
0 голосов
/ 28 июня 2019

У меня есть данные, вложенные в 3 уровня, которые мне нужно динамически обновлять. Главное, что элементы среднего уровня должны отображаться в ТОП элементов для низкого уровня из-за некоторого поведения при наведении, которое мне нужно, поэтому у меня возникли проблемы с тем, что входит в шаблон ввода / обновления / выхода / слияния должен выглядеть так. (Для верхнего уровня не нужно отображать какие-либо элементы).

Код, который я сейчас имею, успешно обновляет данные, но не отображает прямоугольники вообще, вместо этого выдает ошибку Uncaught TypeError: this.setAttribute is not a function.

Как мне решить эту проблему, пожалуйста?

Вот как это должно выглядеть перед обновлением:

image

А вот как это должно выглядеть после обновления:

image

Вот кодовая ручка с кодом ниже

```
let width = 0.9 * window.innerWidth,
 height = 0.9 * window.innerHeight,
 colors = ['darkviolet', 'steelblue', 'coral', 'Turquoise', 'firebrick', 'mediumslateblue', 'palevioletred', 'green', 'aqua'];

let data1 = 
 [{"group":"A","segment":"1","item":"1"},
  {"group":"A","segment":"1","item":"2"},
  {"group":"A","segment":"1","item":"3"},
  {"group":"A","segment":"2","item":"4"},
  {"group":"A","segment":"2","item":"5"},
  {"group":"A","segment":"2","item":"6"},
  {"group":"A","segment":"3","item":"7"},
  {"group":"A","segment":"3","item":"8"},
  {"group":"A","segment":"3","item":"9"},
  {"group":"B","segment":"4","item":"1"},
  {"group":"B","segment":"4","item":"2"},
  {"group":"B","segment":"4","item":"3"},
  {"group":"B","segment":"5","item":"4"},
  {"group":"B","segment":"5","item":"5"},
  {"group":"B","segment":"5","item":"6"},
  {"group":"B","segment":"6","item":"7"},
  {"group":"B","segment":"6","item":"8"},
  {"group":"B","segment":"6","item":"9"},
  {"group":"C","segment":"7","item":"1"},
  {"group":"C","segment":"7","item":"2"},
  {"group":"C","segment":"7","item":"3"},
  {"group":"C","segment":"8","item":"4"},
  {"group":"C","segment":"8","item":"5"},
  {"group":"C","segment":"8","item":"6"},
  {"group":"C","segment":"9","item":"7"},
  {"group":"C","segment":"9","item":"8"},
  {"group":"C","segment":"9","item":"9"}],
 
data2 = 
 [{"group":"A","segment":"1","item":"1"},
  {"group":"A","segment":"8","item":"2"},
  {"group":"A","segment":"9","item":"3"},
  {"group":"A","segment":"2","item":"4"},
  {"group":"A","segment":"2","item":"5"},
  {"group":"A","segment":"2","item":"6"},
  {"group":"A","segment":"5","item":"7"},
  {"group":"A","segment":"3","item":"8"},
  {"group":"A","segment":"3","item":"9"},
  {"group":"B","segment":"4","item":"1"},
  {"group":"B","segment":"4","item":"2"},
  {"group":"B","segment":"7","item":"3"},
  {"group":"B","segment":"5","item":"4"},
  {"group":"B","segment":"5","item":"5"},
  {"group":"B","segment":"5","item":"6"},
  {"group":"B","segment":"5","item":"7"},
  {"group":"B","segment":"6","item":"8"},
  {"group":"B","segment":"6","item":"9"},
  {"group":"C","segment":"7","item":"1"},
  {"group":"C","segment":"7","item":"2"},
  {"group":"C","segment":"3","item":"3"},
  {"group":"C","segment":"8","item":"4"},
  {"group":"C","segment":"8","item":"5"},
  {"group":"C","segment":"8","item":"6"},
  {"group":"C","segment":"9","item":"7"},
  {"group":"C","segment":"6","item":"8"},
  {"group":"C","segment":"1","item":"9"}]; 

let button = d3.select('body')
.append('button')
.attr('type', 'button')
.style('display', 'block')
.text('Update')
.on('click', function() { update(data2) });

var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.append('g');

let color = d3.scaleOrdinal().range(colors);


update(data1);

function getxy(data) {

let grouped = Array.from(d3.group(data, d=> d.group, d=> d.segment), ([key, value]) => ({key, value}));

grouped.forEach(function(s) {
	s.value = Array.from(s.value, ([key, value]) => ({key, value}));
	s.value.forEach(function(d) {
		d.start = d3.min(d.value, function(t) { t.segment = +t.segment; t.item = +t.item; return +t.item });
		d.end = d3.max(d.value, function(t) { return t.item });
		d.key = +d.key;
		d.group = s.key;
	})
})

let x1 = d3.scaleBand()
	.domain([1, 2, 3, 4, 5, 6, 7, 8, 9])
	.range([width*0.05, width])
	.padding(0.0);

let y1 = d3.scaleBand()
	.domain(['A', 'B', 'C'])
	.range([10, height])
	.padding(0.1);

return [x1, y1, grouped];

}

function update(data) {
let xy = getxy(data);
let x = xy[0], y = xy[1], groupedData = xy[2];


let barsAll = svg
	.selectAll('.bars')
	.data(groupedData);

barsAll.exit().remove();

let barsEnter = barsAll
	.enter()
	.append('g')
	.attr('class', 'bars');

barsEnter = barsEnter.merge(barsAll);

let segmentsAll = barsEnter
	.selectAll('.segments')
	.data(function(d) { return d.value });

segmentsAll.exit().remove();
	
let segmentsEnter = segmentsAll.enter();

let bitsAll = segmentsEnter
	.selectAll('.bits')
	.data(function(d) { return d.value });

bitsAll.exit().remove();

let bitsEnter = bitsAll
	.enter()
	.append('circle')
	.attr('class', 'bits')
	.attr('r', width*0.05)
	.attr('stroke', 'none');

bitsEnter = bitsEnter.merge(bitsAll);

bitsEnter
	.attr('cx', function(d) { return x(d.item) })
	.attr('cy', function(d) { return y(d.group) + y.bandwidth()/2 })
	.attr('fill', function(d) { return color(d.segment) });

	
segmentsEnter.append('rect')
	.attr('stroke', 'black')
	.attr('class', 'segments')
	.style('fill-opacity', 0.2);

segmentsEnter = segmentsEnter.merge(segmentsAll);

segmentsEnter
	.attr('fill', function(d) { return color(d.key) })
	.attr('height', y.bandwidth()*0.75)
	.attr('x', function(d) { return x(d.start) - width*0.05 })
	.attr('y', function(d) { return y(d.group) + y.bandwidth()*0.125 })
	.attr('width', function(d) { return x(d.end) - x(d.start) + width*0.1 });
}
```
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-array.v2.min.js"></script>

1 Ответ

0 голосов
/ 29 июня 2019

Что ж, пройдя этап «слияния» на сегментах среднего уровня и битах низкого уровня (но не на столбцах верхнего уровня), я наконец смог взломать исправление. Рабочая ручка

Все еще открыта, чтобы помогать другим, потому что я чувствую, что должна действительно овладеть всем потоком - обновлять, вводить, выходить, объединять - в какой-то момент.

let width = 0.9 * window.innerWidth,
	 height = 0.9 * window.innerHeight,
	 colors = ['darkviolet', 'steelblue', 'coral', 'Turquoise', 'firebrick', 'mediumslateblue', 'palevioletred', 'green', 'aqua'];


let data1 = 
	 [{"group":"A","segment":"1","item":"1"},
	  {"group":"A","segment":"1","item":"2"},
	  {"group":"A","segment":"1","item":"3"},
	  {"group":"A","segment":"2","item":"4"},
	  {"group":"A","segment":"2","item":"5"},
	  {"group":"A","segment":"2","item":"6"},
	  {"group":"A","segment":"3","item":"7"},
	  {"group":"A","segment":"3","item":"8"},
	  {"group":"A","segment":"3","item":"9"},
	  {"group":"B","segment":"4","item":"1"},
	  {"group":"B","segment":"4","item":"2"},
	  {"group":"B","segment":"4","item":"3"},
	  {"group":"B","segment":"5","item":"4"},
	  {"group":"B","segment":"5","item":"5"},
	  {"group":"B","segment":"5","item":"6"},
	  {"group":"B","segment":"6","item":"7"},
	  {"group":"B","segment":"6","item":"8"},
	  {"group":"B","segment":"6","item":"9"},
	  {"group":"C","segment":"7","item":"1"},
	  {"group":"C","segment":"7","item":"2"},
	  {"group":"C","segment":"7","item":"3"},
	  {"group":"C","segment":"8","item":"4"},
	  {"group":"C","segment":"8","item":"5"},
	  {"group":"C","segment":"8","item":"6"},
	  {"group":"C","segment":"9","item":"7"},
	  {"group":"C","segment":"9","item":"8"},
	  {"group":"C","segment":"9","item":"9"}],
	 
	data2 = 
	 [{"group":"A","segment":"1","item":"1"},
	  {"group":"A","segment":"8","item":"2"},
	  {"group":"A","segment":"9","item":"3"},
	  {"group":"A","segment":"2","item":"4"},
	  {"group":"A","segment":"2","item":"5"},
	  {"group":"A","segment":"2","item":"6"},
	  {"group":"A","segment":"5","item":"7"},
	  {"group":"A","segment":"3","item":"8"},
	  {"group":"A","segment":"3","item":"9"},
	  {"group":"B","segment":"4","item":"1"},
	  {"group":"B","segment":"4","item":"2"},
	  {"group":"B","segment":"7","item":"3"},
	  {"group":"B","segment":"5","item":"4"},
	  {"group":"B","segment":"5","item":"5"},
	  {"group":"B","segment":"5","item":"6"},
	  {"group":"B","segment":"5","item":"7"},
	  {"group":"B","segment":"6","item":"8"},
	  {"group":"B","segment":"6","item":"9"},
	  {"group":"C","segment":"7","item":"1"},
	  {"group":"C","segment":"7","item":"2"},
	  {"group":"C","segment":"3","item":"3"},
	  {"group":"C","segment":"8","item":"4"},
	  {"group":"C","segment":"8","item":"5"},
	  {"group":"C","segment":"8","item":"6"},
	  {"group":"C","segment":"9","item":"7"},
	  {"group":"C","segment":"6","item":"8"},
	  {"group":"C","segment":"1","item":"9"}]; 

let button = d3.select('body')
	.append('button')
	.attr('type', 'button')
	.style('display', 'block')
	.text('Update')
	.on('click', function() { update(data2) });

var svg = d3.select('body').append('svg')
	.attr('width', width)
	.attr('height', height)
	.append('g');

let color = d3.scaleOrdinal().range(colors);

function getxy(data) {
	
	let grouped = Array.from(d3.group(data, d=> d.group, d=> d.segment), ([key, value]) => ({key, value}));
	
	grouped.forEach(function(s) {
		s.value = Array.from(s.value, ([key, value]) => ({key, value}));
		s.value.forEach(function(d) {
			d.start = d3.min(d.value, function(t) { t.segment = +t.segment; t.item = +t.item; return +t.item });
			d.end = d3.max(d.value, function(t) { return t.item });
			d.key = +d.key;
			d.group = s.key;
		})
	})
	
	let x1 = d3.scaleBand()
		.domain([1, 2, 3, 4, 5, 6, 7, 8, 9])
		.range([width*0.05, width])
		.padding(0.0);

	let y1 = d3.scaleBand()
		.domain(['A', 'B', 'C'])
		.range([10, height])
		.padding(0.1);
	
	return [x1, y1, grouped];

}

function update(data) {
	let xy = getxy(data);
	let x = xy[0], y = xy[1], groupedData = xy[2];

	// update
	let barsAll = svg
		.selectAll('.bars')
		.data(groupedData);
	
	// exit
	barsAll.exit().remove();
	
	// enter
	let barsEnter = barsAll
		.enter();
	
	barsEnter = barsEnter.merge(barsAll).append('g');
	
	barsEnter.selectAll('.segments').remove();
	
	d3.selectAll('.segments').remove();
	
	let segmentsAll = barsEnter
		.selectAll('.segments')
		.data(function(d) { return d.value });
	
	segmentsAll.exit().remove();
		
	let segmentsEnter = segmentsAll
		.enter();
	
	let bitsAll = segmentsEnter
		.selectAll('.bits')
		.data(function(d) { return d.value });
	
	bitsAll.exit().remove();
	
	bitsAll
		.enter()
		.append('circle')
		.attr('class', 'bits')
		.attr('r', width*0.05)
		.attr('stroke', 'none')
		.attr('cx', function(d) { return x(d.item) })
		.attr('cy', function(d) { return y(d.group) + y.bandwidth()/2 })
		.attr('fill', function(d) { return color(d.segment) });
	
//	bitsEnter = bitsEnter.merge(bitsAll);
	
	bitsAll
		.attr('cx', function(d) { return x(d.item) })
		.attr('cy', function(d) { return y(d.group) + y.bandwidth()/2 })
		.attr('fill', function(d) { return color(d.segment) });

	segmentsEnter
		.append('rect')
		.attr('class', 'segments')
		.attr('stroke', 'black')
		.style('fill-opacity', 0.2)
		.attr('fill', function(d) { return color(d.key) })
		.attr('height', function() { return y.bandwidth()*0.75 })
		.attr('x', function(d) { return x(d.start) - width*0.05 })
		.attr('y', function(d) { return y(d.group) + y.bandwidth()*0.125 })
		.attr('width', function(d) { return x(d.end) - x(d.start) + width*0.1 });
	
	segmentsAll
		.attr('fill', function(d) { return color(d.key) })
		.attr('height', function() { return y.bandwidth()*0.75 })
		.attr('x', function(d) { return x(d.start) - width*0.05 })
		.attr('y', function(d) { return y(d.group) + y.bandwidth()*0.125 })
		.attr('width', function(d) { return x(d.end) - x(d.start) + width*0.1 });
	
	//segmentsAll = segmentsEnter.merge(segmentsAll);

	// segmentsEnter
	// 	.attr('fill', function(d) { return color(d.key) })
	// 	.attr('height', function() { return y.bandwidth()*0.75 })
	// 	.attr('x', function(d) { return x(d.start) - width*0.05 })
	// 	.attr('y', function(d) { return y(d.group) + y.bandwidth()*0.125 })
	// 	.attr('width', function(d) { return x(d.end) - x(d.start) + width*0.1 });
		
}
update(data1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>
<script src="https://d3js.org/d3-array.v2.min.js"></script>
...