D3嵌套的追加,包含更新,选择问题

时间:2018-06-22 12:55:06

标签: javascript d3.js

D3选择烤我的面条!

我有一系列嵌套选择,需要根据输入字段进行更新。我有4个工作中有3个。主要问题是第三个选择更新 innerSArray ,黄色条形未更新。我认为问题来自于更深层次的问题,但不确定。我不得不.merge()以前的选择。

要更新嵌套的.append(),我已经做了一个新的d3.selectAll(),但是不确定这是否是正确的方法。我已经针对 innerM innerSM 做到了这一点。

如何才能正确更新第三个选择?我应该把嵌套的附件拆开吗?

.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 increment = document.getElementById('increment');
      const incrementM = document.getElementById('incrementM');
      const incrementSR = document.getElementById('incrementSR');
      const incrementSM = document.getElementById('incrementSM');
      const anchor = d3.select('#anchor');
      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);

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

        // UPDATE INNER
        inner
          .transition()
          .duration(1000)
          .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'; })
            .append('div')
              .attr("class", "innerM")
              .style('width', function(d) { return d.m+'px'; })
            //.merge(inner); I think there might be an issue here, removing it helps, but not a complete fix
        
        // UPDATE INNER-M - Not sure if this is the best way to update
        let innerM = d3.selectAll('.innerM')
          .transition()
          .duration(1000)
          .style('width', function(d) { return d.m*incrementM.value+'px'; });
        
        
        // Child array
        let innerSArray = inner.selectAll('.innerM').data(function(d) { return d.s; })
        
        innerSArray // This doen't get updated
          .transition()
          .duration(1000)
          .style('width', function(d) { console.log(d.r); return d.r*incrementSR.value+'px'; });
            
        innerSArray.exit().remove()
        
        innerSArray = innerSArray.enter()
          .append('div')
            .attr('class','sr')
            .style('width', function(d) { return d.r+'px'; })
          .append('div')
            .attr('class','sm')
            .style('width', function(d) { return d.m+'px'; })
          .merge(innerSArray);
          
        // UPDATE INNER-SM - Not sure if this is the best way to update
        let innerSM = d3.selectAll('.sm')
          .transition()
          .duration(1000)
          .style('width', function(d) { return d.m*incrementSM.value+'px'; });
        
      }
      
      //run once
      update(data);
  
    </script>
  </body>
  </html>

1 个答案:

答案 0 :(得分:0)

我设法通过将.inner选择项上的双重追加拆分为自己的嵌套选择项来解决此问题。这需要将.innerM的返回数据包装在数组文字中。然后,我得以继续嵌套选择。在发布此问题之前,我以前曾以这种方式进行过尝试,但是数据结构还有另一个问题。并非在每个对象中都声明了s数组。即完全缺少s属性,而不是一个空数组。这导致数据联接出现问题。

.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>