0

I have made a D3 line chart, which is drawn by the textarea input data, now I need to redraw or refresh the line chart every time when any user changes the data of textarea. I have already made a code for drawing the chart but not able to refresh it everytime on textarea data change, Please take a look at the code.

var text = document.getElementById('test').value;
var data = text.trim().split('\n').map(line => {
  let tokens = line.trim().split(/\s+/).map(str => parseInt(str, 10));
  return { a: tokens[0], b: tokens[1] };
});

var xExtent = d3.extent(data, function(d) { return d.a; }),
 xRange = xExtent[1] - xExtent[0],
 yExtent = d3.extent(data, function(d) { return d.b; }).reverse(),
 yRange = yExtent[1] - yExtent[0];

var margin = {top: 10, right: 30, bottom: 50, left: 30}
  , width = window.innerWidth - margin.left - margin.right
  , height = window.innerHeight - margin.top - margin.bottom;

var xScale = d3.scaleLinear().range([0, width]).domain([xExtent[0] - (xRange * .05), xExtent[1] + (xRange * .05)]);;
var yScale = d3.scaleLinear().range([0, height]).domain([yExtent[0] - (yRange * .05), yExtent[1] + (yRange * .05)]);;
   
var line = d3.line()
    .x(function(d, a) { return xScale(d.a); })
    .y(function(d, b) { return yScale(d.b); })
    .curve(d3.curveMonotoneX)

var svg = d3.select(".graph").append("svg")
    .attr("width", width + margin.left + margin.right - 10)
    .attr("height", height + margin.top + margin.bottom - 20)
   .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(xScale));

svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale));

svg.append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);
.line {fill: none;stroke: #ffab00;stroke-width: 3}
<textarea id='test'>
1 332
2 432
3 212
4 543
5 125
6 343
7 445
</textarea>
<div class='graph' style='height:50%'/>
<script src="https://d3js.org/d3.v5.min.js"></script>
Insta nano
  • 59
  • 7
  • add your graph generation code in one function and use `onkeyup` event in text area on that `onkeyup` event call that graph regeneration function. for `onkeyup` event refer this post [on change / on key up](https://stackoverflow.com/questions/2823733/textarea-onchange-detection) – turivishal Jun 03 '20 at 19:18

1 Answers1

0

You need to put the drawing of your chart into a function that you can call when you need to update it. Then you need to respond to the user input, perhaps with a button, and get the data from your textarea again and update the chart.

I made a jsfiddle which shows the sort of thing you need to do. It will create the chart initially and then update the chart each time the button is pressed. However, you need to modify it to use D3s general update pattern with enter, update and exit phases, and sort out the axis. Take a look at this bl.ocks.org page for an example of this.

jsfiddle

document.getElementById('update').addEventListener('click', function (e) {
    console.log('click')
  drawChart(getData());
})

function getData() {
    var text = document.getElementById('test').value;
    var data = text.trim().split('\n').map(line => {
    let tokens = line.trim().split(/\s+/).map(str => parseInt(str, 10));
    return { a: tokens[0], b: tokens[1] };
  });

  return data;
}

function drawChart(data) {
  var xExtent = d3.extent(data, function(d) { return d.a; }),
    xRange = xExtent[1] - xExtent[0],
    yExtent = d3.extent(data, function(d) { return d.b; }).reverse(),
    yRange = yExtent[1] - yExtent[0];

  var margin = {top: 10, right: 30, bottom: 50, left: 30}
    , width = window.innerWidth - margin.left - margin.right
    , height = window.innerHeight - margin.top - margin.bottom;

  var xScale = d3.scaleLinear().range([0, width]).domain([xExtent[0] - (xRange * .05), xExtent[1] + (xRange * .05)]);;
  var yScale = d3.scaleLinear().range([0, height]).domain([yExtent[0] - (yRange * .05), yExtent[1] + (yRange * .05)]);;

  var line = d3.line()
      .x(function(d, a) { return xScale(d.a); })
      .y(function(d, b) { return yScale(d.b); })
      .curve(d3.curveMonotoneX)

  var svg = d3.select(".graph")
      .attr("width", width + margin.left + margin.right - 10)
      .attr("height", height + margin.top + margin.bottom - 20)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(xScale));

  svg.append("g")
      .attr("class", "y axis")
      .call(d3.axisLeft(yScale));

  svg.append("path")
      .datum(data)
      .attr("class", "line")
    .attr("d", line);
}

drawChart(getData());

I changed your div to an svg element and removed the .append from the JS otherwise it would be appending a new graph each time.

<textarea id='test'>
1   332
2   432
3   212
4   543
5   125
6   343
7   445
</textarea>
<button id="update">update</button>
<svg class='graph' style='height:50%'/>

I hope this gives you enough info to continue.

Bryan
  • 657
  • 3
  • 10
  • Dear Dev, please help again with some problem, I want to draw another chart on the same page after changing some data in the previous json data, new data generating command, const newData = data.map(d => ({...d, x:d.x*2.5, y:d.y*1.5.toFixed(4)})); – Insta nano Jun 04 '20 at 12:20
  • by using this command I am able to generate new j son data string but when I create new function drawChart(newData), but it is not working – Insta nano Jun 04 '20 at 12:24
  • @Instanano I'd suggest two svg elements, one for each chart, and then have a second parameter on drawchart(data, chartId). Then you can call your drawChart function and pass in the data to use and svg element to use. I think that's probably the way I'd tackle it. – Bryan Jun 04 '20 at 14:18
  • Sir I have tried but not wokring. please make a working jsfiddle, your valuable time is highly appreciated. – Insta nano Jun 04 '20 at 14:53
  • I have even posted a new question with all the data I have here on this this link - https://stackoverflow.com/questions/62196190/draw-multiple-d3-charts-on-same-page-with-calculations-from-previous-chart – Insta nano Jun 04 '20 at 14:54