d3 v4 axis not updating

时间:2018-09-22 23:02:07

标签: javascript d3.js

I'm currently making a simple line chart that updates its values based on a series of input forms.

I can create and render the chart correctly, and can update the line upon user input, however my axis labels aren't updating in turn. I've tried following a few other examples here but to no avail, can someone please help me in fixing my updateData() function to update the axis labels in my code?

jsfiddle - https://jsfiddle.net/quirkules/0xktoLj7/1/

  //****** CREATE CHART ******

  //collect data from input fields
  var data = [];
  for (var i = 0; i < 10; i++) {
    data.push({
      x: d3.select('#cadenceThroughputData' + i).select('input').property('value'),
      y: d3.select('#cadenceLengthData' + i).select('input').property('value'),
    });
  }

  // set the dimensions and margins of the graph
  var margin = {top: 20, right: 20, bottom: 30, left: 50},
      width = d3.select('#output-chart').node().getBoundingClientRect().width - margin.left - margin.right,
      height = d3.select('#output-chart').node().getBoundingClientRect().height - margin.top - margin.bottom;

  // set the ranges
  var x = d3.scaleLinear().range([0, width]);
  var y = d3.scaleLinear().range([height, 0]);

  var x_axis = d3.axisBottom().scale(x);
  var y_axis = d3.axisLeft().scale(y);

  // define the line
  var valueline = d3.line()
    .x(d => { return x(d.x); })
    .y(d => { return y(d.y); });

  // append the svg obgect to the body of the page
  // appends a 'group' element to 'svg'
  // moves the 'group' element to the top left margin
  var svg = d3.select("#output-chart")
      .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  // format the data
  data.forEach(function(d) {
      d.x = +d.x;
      d.y = +d.y;
  });

  // Scale the range of the data
  x.domain([0, d3.max(data, d => { return d.x; })]);
  y.domain([0, d3.max(data, d => { return d.y; })]);

  // Add the valueline path.
  svg.append("path")
      .data([data])
      .attr("class", "line")
      .attr("d", valueline);

  // Add the X Axis
  svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(x_axis);

  // Add the Y Axis
  svg.append("g")
      .call(y_axis);

  function updataData(){
    //collect data from input fields again
    var data = [];
    for (var i = 0; i < 10; i++) {
      data.push({
        x: d3.select('#cadenceThroughputData' + i).select('input').property('value'),
        y: d3.select('#cadenceLengthData' + i).select('input').property('value'),
      });
    }

    // format the data
    data.forEach(function(d) {
        d.x = +d.x;
        d.y = +d.y;
    });

    // Scale the range of the data again
    x.domain([0, d3.max(data, d => { return d.x; })]);
    y.domain([0, d3.max(data, d => { return d.y; })]);

    // Select the section we want to apply our changes to
    var svg = d3.select("#output-chart").transition();

    // Make the changes
    // change the line
    svg.select(".line")
      .duration(750)
      .attr("d", valueline(data));
    // change the x axis
    svg.select(".x") 
      .duration(750)
      .call(x_axis);
    // change the y axis
    svg.select(".y") 
      .duration(750)
      .call(y_axis);
  }

  //****** END CREATE CHART ******

1 个答案:

答案 0 :(得分:1)

微小变化:

主要问题的解决方案,即轴未更新=>您正在调用select('.x'),但是在创建 x y 轴时错过了添加类的操作。

    svg.append("g").attr('class', 'x')....


    svg.append("g").attr('class', 'y')...

代码的一些补充(也许您可以将其作为我的建议):

  1. 通常,折线图只是一条简单的线,没有显示填充区域。为此,请进行以下更改(添加到path后),或者您可以添加CSS:

    .style('fill', 'none')
    .style('stroke', '#000')
    
  2. .header不需要任何填充。调整大小时看起来混乱了。删除了.header { /* padding: 20px 0px 20px 0px; */ }

  3. 也许您错过了这一点,但是y列输入并没有在更改时调用updateData()

    d3.select('#input-cadenceLengthData')
    ...
    .append('input')
    .on('input', updataData)
    

将以上所有内容放在一起,这是一个小提琴:https://jsfiddle.net/nq1rfy7c/

摘要:

  //****** SETUP DIVS ******

  // Add the divs to the DOM
  $(document.body)
    .append('<div id="global-header"></div>')
    .append('<div id="input-cadenceSelect"></div>')
    .append('<div id="input-cadenceThroughputHeader"></div>')
    .append('<div id="input-cadenceLengthHeader"></div>')
    .append('<div id="input-cadenceType"></div>')
    .append('<div id="input-cadenceThroughputData"></div>')
    .append('<div id="input-cadenceLengthData"></div>')
    .append('<div id="output-chart"></div>')
    .append('<div id="output-summary"></div>')
    .append('<div id="global-footer"></div>');

  //add text to #input-cadenceThroughputHeader
  d3.select('#input-cadenceThroughputHeader')
    .append('label')
    .text('X Value');
  d3.select('#input-cadenceLengthHeader')
    .append('label')
    .text('Y Value');
    
  for (var i = 0; i < 10; i++) {
    //add 10 #cadenceType divs to #input-cadenceType
    d3.select('#input-cadenceType')
      .append('div')
      .attr('class', 'header')
      .attr('id', 'cadenceType' + i)
      .style('position', 'absolute')
      .style('top', (i * 10) + '%')
      .style('width', '100%')
      .style('height', '10%')
      .style('display', 'table')
      .style('background', bandColour(i))
      .append('label')
      .text((i + 1));

    //add 10 #cadenceData divs to #input-cadenceData
    d3.select('#input-cadenceThroughputData')
      .append('div')
      .attr('id', 'cadenceThroughputData' + i)
      .style('position', 'absolute')
      .style('top', (i * 10) + '%')
      .style('width', '100%')
      .style('height', '10%')
      .style('background', bandColour(i))
      .append('input')
      .on('input', updataData)
      .attr('size', '6')
      .attr('maxlength', '4')
      .style('height', '20px')
      .style('background', bandColour(i))
      .attr('value', parseInt(Math.random() * 100));

    //add 10 #cadenceLength divs to #input-cadenceLength
    d3.select('#input-cadenceLengthData')
      .append('div')
      .attr('id', 'cadenceLengthData' + i)
      .style('position', 'absolute')
      .style('top', (i * 10) + '%')
      .style('width', '100%')
      .style('height', '10%')
      .style('background', bandColour(i))
      .append('input')
      .attr('size', '6')
      .attr('maxlength', '4')
      .style('height', '20px')
      .style('background', bandColour(i))
      .on('input', updataData)
      .attr('value', parseInt(Math.random() * 10));
  }

  function bandColour(i) {
    if (i % 2 > 0) {
      return '#333';
    } else {
      return '#171213';
    }
  }

  //****** END SETUP DIVS ******

  //****** CREATE CHART ******

  //collect data from input fields
  var data = [];
  for (var i = 0; i < 10; i++) {
    data.push({
      x: d3.select('#cadenceThroughputData' + i).select('input').property('value'),
      y: d3.select('#cadenceLengthData' + i).select('input').property('value'),
    });
  }

  // set the dimensions and margins of the graph
  var margin = {
      top: 20,
      right: 20,
      bottom: 30,
      left: 50
    },
    width = d3.select('#output-chart').node().getBoundingClientRect().width - margin.left - margin.right,
    height = d3.select('#output-chart').node().getBoundingClientRect().height - margin.top - margin.bottom;

  // set the ranges
  var x = d3.scaleLinear().range([0, width]);
  var y = d3.scaleLinear().range([height, 0]);

  var x_axis = d3.axisBottom().scale(x);
  var y_axis = d3.axisLeft().scale(y);

  // define the line
  var valueline = d3.line()
    .x(d => {
      return x(d.x);
    })
    .y(d => {
      return y(d.y);
    });

  // append the svg obgect to the body of the page
  // appends a 'group' element to 'svg'
  // moves the 'group' element to the top left margin
  var svg = d3.select("#output-chart")
    .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  // format the data
  data.forEach(function(d) {
    d.x = +d.x;
    d.y = +d.y;
  });

  // Scale the range of the data
  x.domain([0, d3.max(data, d => {
    return d.x;
  })]);
  y.domain([0, d3.max(data, d => {
    return d.y;
  })]);

  // Add the valueline path.
  svg.append("path")
    .data([data])
    .attr("class", "line")
    .style('fill', 'none')
    .style('stroke', '#000')
    .attr("d", valueline);

  // Add the X Axis
  svg.append("g").attr('class', 'x')
    .attr("transform", "translate(0," + height + ")")
    .call(x_axis);

  // Add the Y Axis
  svg.append("g").attr('class', 'y')
    .call(y_axis);

  function updataData() {
    //collect data from input fields again
    var data = [];
    for (var i = 0; i < 10; i++) {
      data.push({
        x: d3.select('#cadenceThroughputData' + i).select('input').property('value'),
        y: d3.select('#cadenceLengthData' + i).select('input').property('value'),
      });
    }

    // format the data
    data.forEach(function(d) {
      d.x = +d.x;
      d.y = +d.y;
    });

    x_axis = d3.axisBottom().scale(x);
    y_axis = d3.axisLeft().scale(y);

    // Scale the range of the data again
    x.domain([0, d3.max(data, d => {
      return d.x;
    })]);
    y.domain([0, d3.max(data, d => {
      return d.y;
    })]);

    // Select the section we want to apply our changes to
    var svg = d3.select("#output-chart").transition();

    // Make the changes
    // change the line
    svg.select(".line")
      .duration(750)
      .attr("d", valueline(data));
    // change the x axis
    svg.select(".x")
      .duration(750)
      .call(x_axis);
    // change the y axis
    svg.select(".y")
      .duration(750)
      .call(y_axis);
  }

  //****** END CREATE CHART ******
body {
  font-family: sans-serif;
  color: white;
  background: #171213;
}

label {
  display: block;
}

input,
textarea {
  color: white;
  font-size: 18px;
  font-weight: bold;
  text-align: center;
  border: 2px solid transparent;
}

#global-header {
  position: fixed;
  left: 0px;
  top: 0px;
  height: 5%;
  width: 100%;
  padding: 10px;
  box-sizing: border-box;
  text-align: center;
  font-size: 1.5em;
  font-family: Helvetica;
  color: white;
}

.header {
  color: #009DE0;
  font-size: 18px;
  font-weight: bold;
  text-align: center;
  display: table-cell;
  vertical-align: middle;
 /* padding: 20px 0px 20px 0px; */
}

#input-cadenceType {
  position: fixed;
  box-sizing: border-box;
  border-left: 2px solid #009DE0;
  border-top: 2px solid #009DE0;
  border-bottom: 2px solid #009DE0;
  margin-left: 0%;
  top: 25%;
  width: 10%;
  height: 73%;
}

#input-cadenceThroughputHeader {
  position: fixed;
  color: #009DE0;
  font-size: 12px;
  font-weight: bold;
  text-align: center;
  box-sizing: border-box;
  border-left: 2px solid #009DE0;
  border-top: 2px solid #009DE0;
  margin-left: 10%;
  top: 20%;
  width: 10%;
  height: 5%;
  text-align: center;
}

#input-cadenceLengthHeader {
  position: fixed;
  color: #009DE0;
  font-size: 12px;
  font-weight: bold;
  text-align: center;
  box-sizing: border-box;
  border-left: 2px solid #009DE0;
  border-top: 2px solid #009DE0;
  margin-left: 20%;
  top: 20%;
  width: 10%;
  height: 5%;
  text-align: center;
}

#input-cadenceThroughputData {
  position: fixed;
  box-sizing: border-box;
  border-top: 2px solid #009DE0;
  border-left: 2px solid #009DE0;
  border-bottom: 2px solid #009DE0;
  margin-left: 10%;
  top: 25%;
  width: 10%;
  height: 73%;
}

#input-cadenceLengthData {
  position: fixed;
  box-sizing: border-box;
  border-top: 2px solid #009DE0;
  border-left: 2px solid #009DE0;
  border-bottom: 2px solid #009DE0;
  margin-left: 20%;
  top: 25%;
  width: 10%;
  height: 73%;
}

#input-simConstraint {
  position: fixed;
  margin-left: 30%;
  top: 5%;
  width: 35%;
  height: 20%;
  background: aqua;
  text-align: right;
}

#input-simDataHeader {
  position: fixed;
  margin-left: 65%;
  top: 5%;
  width: 35%;
  height: 5%;
  background: orange;
  text-align: center;
}

#input-simDataNoStoriesHeader {
  position: fixed;
  margin-left: 65%;
  top: 10%;
  width: 11.67%;
  height: 5%;
  background: green;
  text-align: center;
}

#input-simDataFocusHeader {
  position: fixed;
  margin-left: 76.67%;
  top: 10%;
  width: 11.67%;
  height: 5%;
  background: silver;
  text-align: center;
}

#input-simDataLengthHeader {
  position: fixed;
  margin-left: 88.34%;
  top: 10%;
  width: 11.67%;
  height: 5%;
  background: goldenrod;
  text-align: center;
}

#input-simDataNoStoriesValue {
  position: fixed;
  margin-left: 65%;
  top: 15%;
  width: 11.67%;
  height: 5%;
  background: pink;
  text-align: center;
}

#input-simDataFocusValue {
  position: fixed;
  margin-left: 76.67%;
  top: 15%;
  width: 11.67%;
  height: 5%;
  background: navy;
  text-align: center;
}

#output-chart {
  position: fixed;
  margin-left: 30%;
  top: 20%;
  width: 70%;
  height: 58%;
  background: red;
  text-align: right;
}

#global-footer {
  position: fixed;
  background: #171213;
  left: 0px;
  bottom: 0px;
  height: 2%;
  width: 100%;
  vertical-align: middle;
  text-align: right;
  font-size: 0.75em;
  font-family: Helvetica;
  color: white;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

希望这会有所帮助。