score:0

Accepted answer

I managed to solve this by splitting the double append on the .inner selection to it's own nested selection. This required wrapping .innerM's returned data in an array literal. I was then able to continue nesting selections. I had previously tried it this way, before posting this question, but had another issue with the structure of the data. The s array wasn't being declared in every object. i.e. missing the s property entirely instead of being an empty array. This caused issues with the data join.

.outer {
			border: 1px solid black;
			background-color: grey;
			width: 100%;
			height: 100px;
			position: relative;
			display: flex;
		}
		.inner {
			display: flex;
			justify-content: flex-start;
			border: 1px solid blue;
			background-color: cyan;
			height: 50px;
			position: relative;
		}
		.innerM {
			display: flex;
			border: 1px solid blue;
			background-color: magenta;
			height: 25px;
			position: relative;
		}
		.sr {
			display: flex;
			background-color: yellow;
			height: 12px;
		}
		.sm {
			display: flex;
			background-color: black;
			height: 6px;
		}
	<!doctype html>
	<html>
	<head>
	<meta charset="UTF-8">
	<title>#</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<script src="https://d3js.org/d3.v5.min.js"></script>
	<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
	</head>
	
	<body>
		<p>Inner: <input id="increment" type="number" value="1" step="1" max="5" /></p>
		<p>InnerM: <input id="incrementM" type="number" value="1" step="1" max="5" /></p>
		<p>SR: <input id="incrementSR" type="number" value="1" step="1" max="5" /></p>
		<p>SM: <input id="incrementSM" type="number" value="1" step="1" max="5" /></p>
		<div id="anchor"></div>
		<script>
			const anchor = d3.select('#anchor');
			
			const increment = document.getElementById('increment');
			const incrementM = document.getElementById('incrementM');
			const incrementSR = document.getElementById('incrementSR');
			const incrementSM = document.getElementById('incrementSM');
			
			const data =  [
				 {
					 "outer": [
						 {
							 "inner": [
								 { "r": 40,
									 "m": 10,
									 "s": []
								 },
								 { "r": 70,
									 "m": 13,
									 "s": []
								 },
								 { "r": 10,
									 "m": 15,
									 "s": [
										 {
											 "r": 20,
											 "m": 5
										 }
									 ] },
								 { "r": 15,
									 "m": 9,
									 "s": []
								 },
								 { "r": 52,
									 "m": 20,
									 "s": []
								 },
								 { "r": 96,
									 "m": 30,
									 "s": [
										 {
											 "r": 50,
											 "m": 10
										 }
									 ] },
								 { "r": 192,
									 "m": 60,
									 "s": []
								 },
								 { "r": 301,
									 "m": 50,
									 "s": []
								 }
							 ]
						 }
					 ]
				 }
			 ];
			
			increment.addEventListener('change', function() {
				update(data);
			});
			
			incrementM.addEventListener('change', function() {
				update(data);
			});
			
			incrementSR.addEventListener('change', function() {
				update(data);
			});
			
			incrementSM.addEventListener('change', function() {
				update(data);
			});
			
			
			function update(data) {

				// main data
				let root = anchor.selectAll('.root').data(data);
				root.exit().remove();
				root = root.enter()
						 .append('div')
						 .attr('class', 'root')
						.merge(root)
				
				// outer array
				let outer = root.selectAll('.outer').data(function(d) { return d.outer });
				outer.exit().remove();
				outer = outer.enter()
									.append('div')
									.attr('class','outer')
								.merge(outer);


				let inner = outer.selectAll('.inner').data(function(d) { return d.inner; });

				inner
					.transition()
					.duration(1000)
					.style('background-color','green')
					.style('width', function(d) { return d.r*increment.value+'px'; });

				inner.exit().remove();

				inner = inner.enter()
						.append('div')
						.attr("class", "inner")
						.style('width', function(d) { return d.r+'px'; })
					.merge(inner);


				let innerM = inner.selectAll('.innerM').data(function(d) { return [d]; });
				
				innerM
					.transition()
					.duration(1000)
					.style('width', function(d) { return d.m*incrementM.value+'px'; });
				
				innerM.exit().remove();
				
				innerM = innerM.enter()
						.append('div')
						.attr("class", "innerM")
						.style('width', function(d) { return d.m+'px'; })
					.merge(innerM)


				let sr = innerM.selectAll('.sr').data(function(d) { return d.s; });
				
				sr
					.transition()
					.duration(1000)
					.style('width', function(d) { return d.r*incrementSR.value+'px'; });
				
				sr.exit().remove();
				
				sr = sr.enter()
						.append('div')
						.attr("class", "sr")
						.style('width', function(d) { return d.r+'px'; })
					.merge(sr)


				let sm = sr.selectAll('.sm').data(function(d) { return [d]; });
				
				sm
					.transition()
					.duration(1000)
					.style('width', function(d) { return d.m*incrementSM.value+'px'; });
				
				sm.exit().remove();
				
				sm = sm.enter()
					.append('div')
					.attr("class", "sm")
					.style('width', function(d) { return d.m+'px'; })

			}
			
			//run once
			update(data);
	
		</script>
	</body>
	</html>


Related Query