首页 > 解决方案 > 如何从输入文本字段将新数据插入条形图中?

问题描述

我有两个输入字段。将插入到 jsdata 对象数组中的名称和值。但是,当我单击提交按钮时,x 域和 y 域似乎无缘无故地被调用了两次。我真的不知道它为什么会重复。我希望图表绘制一个新条,然后按升序排序。

<!DOCTYPE html>

.bar {
    font: 10px sans-serif;
    text-align: right;
    padding: 3px;
    margin: 1px;
    color: white;
}

.axis text {
    font: 10px sans-serif;
}

.axis path,
.axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
}

.x.axis path {
    display: none;
}

.legend rect {
    fill: white;
    stroke: black;
    opacity: 0.8;
}

.toolTip {
    position: absolute;
    display: none;
    min-width: 80px;
    height: auto;
    background: none repeat scroll 0 0 #ffffff;
    border: 1px solid #6F257F;
    padding: 14px;
    text-align: center;
}

.switch {
    position: relative;
    display: inline-block;
    width: 60px;
    height: 34px;
}

.switch input {
    display: none;
}

.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #ccc;
    -webkit-transition: .4s;
    transition: .4s;
}

.slider:before {
    position: absolute;
    content: "";
    height: 26px;
    width: 26px;
    left: 4px;
    bottom: 4px;
    background-color: white;
    -webkit-transition: .4s;
    transition: .4s;
}

input:checked+.slider {
    background-color: #2196F3;
}

input:focus+.slider {
    box-shadow: 0 0 1px #2196F3;
}

input:checked+.slider:before {
    -webkit-transform: translateX(26px);
    -ms-transform: translateX(26px);
    transform: translateX(26px);
}

/* Rounded sliders */

.slider.round {
    border-radius: 34px;
}

.slider.round:before {
    border-radius: 50%;
}

#userdata {

    top: -80px;
}

div {
    display: inline-block;
    position: relative;
}

#colorize {
    position: absolute;
    bottom: 10px;
    right: 10px;
}

#toggle {
    top: -60px;
}
</style>
<svg class="chart"></svg>
<div class="row">
    <div class="col-sm-4">
        <h3>Enter your desired colors in hexadecimal value</h3>
        <textarea rows="6" cols="60" id="colorInput"></textarea>
        <button id="colorize" onclick="colorize()">Colorize</button>
    </div>
    <div class="col-sm-4" id="userdata">
        <h3>Enter your data</h3>
        <input type="text" id="name" placeholder="name">
        <input type="number" id="value" placeholder="value">
        <button onclick="addData()">Submit</button>
    </div>
    <div class="col-sm-4" id="toggle">
        <h3>Toggle Data Label</h3>
        <label class="switch">
            <input type="checkbox" onclick="togglePressed()" checked>
            <span class="slider round"></span>
        </label>
    </div>
</div>
<script src="http://d3js.org/d3.v3.js"></script>
<script src="d3legend.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>

    var jsdata = [
        { name: "Locke", value: 4 },
        { name: "Reyes", value: 8 },
        { name: "Ford", value: 15 },
        { name: "Jarrah", value: 16 },
        { name: "Shephard", value: 23 },
        { name: "Kwon", value: 52 }
    ];

    console.log(typeof jsdata);
    var colorCodes = ["#6b486b", "#a05d56", "#d0743c", "#ff8c00"];
    var color = d3.scale.ordinal().range(colorCodes);
    //Set the margins for the bar chart. 
    var margin = { top: 20, right: 30, bottom: 30, left: 40 },
        width = 960 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom;

    //Encoding ordinal data. rangeRoundBands is used to snap each position to the exact pixel boundary for crisp edges
    var x = d3.scale.ordinal()
        .rangeRoundBands([0, width], .1);

    var y = d3.scale.linear()
        .range([height, 0]);

    var tooltip = d3.select("body").append("div").attr("class", "toolTip");
    //Adding the axes
    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("bottom");

    var yAxis = d3.svg.axis()
        .scale(y)
        .orient("left");

    //Declaring the chart container
    var chart = d3.select(".chart")
        .attr("width", width + margin.left + margin.right)
        .data(jsdata)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");



    x.domain(jsdata.map(function (jsdata) { return jsdata.name; }));
    y.domain([0, d3.max(jsdata, function (jsdata) { return jsdata.value; })]);

    chart.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    chart.append("g")
        .attr("class", "y axis")
        .call(yAxis);

    chart.selectAll(".bar")
        .data(jsdata) // Using the data join pattern
        .enter().append("rect") //Selecting the chart container then append the width and height for new nodes
        .style("fill", function (jsdata, i) { return color(i); })
        .style("color", function () { return '#FFFFFF'; })
        .on("mousemove", function (jsdata) {
            tooltip
                .style("left", d3.event.pageX - 50 + "px")
                .style("top", d3.event.pageY - 70 + "px")
                .style("display", "inline-block")
                .html((jsdata.name) + "<br>" + "£" + (jsdata.value));
        })
        .on("mouseout", function (jsdata) { tooltip.style("display", "none"); })
        .attr("class", "bar")
        .attr("data-legend", function (jsdata) { return jsdata.name })
        .attr("x", function (jsdata) { return x(jsdata.name); })
        .attr("y", function (jsdata) { return y(jsdata.value); })
        .attr("height", function (jsdata) { return height - y(jsdata.value); })
        .attr("width", x.rangeBand());

    chart.selectAll(".text")
        .data(jsdata)
        .enter()
        .append("text")
        .attr("class", "label")
        .attr("x", (function (jsdata) { return x(jsdata.name) + 56; }))
        .attr("y", function (jsdata) { return y(jsdata.value) - 20; })
        .attr("dy", ".75em")
        .text(function (jsdata) { return jsdata.value; });

    /*chart.selectAll("text")
        .data(jsdata)
        .enter()
        .append("text")
        .text(function (jsdata) {
            return jsdata.value;
        })*/

    //Converting the column from name to integer
    function type(jsdata) {
        jsdata.value = +jsdata.value;
        return jsdata;
    }
    function togglePressed() {
        $(".label").toggle();
    }
    function colorize() {
        var lines = $('#colorInput').val().split('\n');
        for (var i = 0; i < lines.length; i++) {
            if (colorCodes.includes(lines[i])) {
                alert("Error. This color already exists.");
            }
            else {

                colorCodes.push(lines[i]);
            }
        }

        chart.selectAll(".bar")
            .style('fill', function (jsdata, i) { return color(i); })
            .attr("height", function (jsdata) { return height - y(jsdata.value); })
            .attr("width", x.rangeBand());


    }
    function addData() {
        var name = document.getElementById("name").value;
        var value = document.getElementById("value").value;

        var person = new Object();
        person.name = name;
        person.value = parseInt(value);

        jsdata.push(person);
        //chart.select(x).remove();
        x.domain(jsdata.map(function (jsdata) { return jsdata.name; }));
        y.domain([0, d3.max(jsdata, function (jsdata) { return jsdata.value; })]);

        chart.select(".xaxis").remove();

        chart.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);

        chart.append("g")
            .attr("class", "y axis")
            .call(yAxis);


        var bars = chart.selectAll(".bar").data(jsdata);
        bars.enter().append("rect")
            .style("fill", function (jsdata, i) { return color(i); })
            .style("color", function () { return '#FFFFFF'; })
            .on("mousemove", function (jsdata) {
                tooltip
                    .style("left", d3.event.pageX - 50 + "px")
                    .style("top", d3.event.pageY - 70 + "px")
                    .style("display", "inline-block")
                    .html((jsdata.name) + "<br>" + "£" + (jsdata.value));
            })
            .on("mouseout", function (jsdata) { tooltip.style("display", "none"); })
            .attr("class", "bar")
            .attr("data-legend", function (jsdata) { return jsdata.name })
            .attr("x", function (jsdata) { return x(jsdata.name); })
            .attr("y", function (jsdata) { return y(jsdata.value); })
            .attr("height", function (jsdata) { return height - y(jsdata.value); })
            .attr("width", x.rangeBand());

        chart.select(".text")
            .data(jsdata)
            .enter()
            .append("text")
            .attr("class", "label")
            .attr("x", (function (jsdata) { return x(jsdata.name) + 56; }))
            .attr("y", (function (jsdata) { return y(jsdata.value) - 20; }))
            .attr("dy", ".75em")
            .text(function (jsdata) { return jsdata.value; });

        /*chart.select("text")
            .data(jsdata)
            .enter()
            .append("text")
            .text(function (jsdata) {
                return jsdata.value;
            })*/

        bars.exit().remove();


    }
    var legend = chart.append("g")
        .attr("class", "legend")
        .attr("transform", "translate(50,30)")
        .attr("data-legend-pos", "bottom")
        .style("font-size", "12px")
        .call(d3.legend);
</script>

截屏: 在此处输入图像描述

标签: htmld3.jssvg

解决方案


您的代码中没有条形图(也没有标签)的更新选择。

您可以利用 D3 v3 具有的神奇行为(从 v4 开始删除),其中append修改更新选择,只做一个小改动:

var bars = chart.selectAll(".bar").data(jsdata);

bars.enter().append("rect")
    //etc...

bars.attr("x", function(jsdata) {
        return x(jsdata.name);
    })
    //etc...

对标签执行相同的操作(顺便说一下,没有text要选择的类)。最后,只需再次调用轴,不要重新附加它们:

chart.select(".x.axis")
    .call(xAxis);

chart.select(".y.axis")
    .call(yAxis);

以下是这些更改的代码:

<!DOCTYPE html>
<style>
  .bar {
    font: 10px sans-serif;
    text-align: right;
    padding: 3px;
    margin: 1px;
    color: white;
  }

  .axis text {
    font: 10px sans-serif;
  }

  .axis path,
  .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }

  .x.axis path {
    display: none;
  }

  .legend rect {
    fill: white;
    stroke: black;
    opacity: 0.8;
  }

  .toolTip {
    position: absolute;
    display: none;
    min-width: 80px;
    height: auto;
    background: none repeat scroll 0 0 #ffffff;
    border: 1px solid #6F257F;
    padding: 14px;
    text-align: center;
  }

  .switch {
    position: relative;
    display: inline-block;
    width: 60px;
    height: 34px;
  }

  .switch input {
    display: none;
  }

  .slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #ccc;
    -webkit-transition: .4s;
    transition: .4s;
  }

  .slider:before {
    position: absolute;
    content: "";
    height: 26px;
    width: 26px;
    left: 4px;
    bottom: 4px;
    background-color: white;
    -webkit-transition: .4s;
    transition: .4s;
  }

  input:checked+.slider {
    background-color: #2196F3;
  }

  input:focus+.slider {
    box-shadow: 0 0 1px #2196F3;
  }

  input:checked+.slider:before {
    -webkit-transform: translateX(26px);
    -ms-transform: translateX(26px);
    transform: translateX(26px);
  }

  /* Rounded sliders */

  .slider.round {
    border-radius: 34px;
  }

  .slider.round:before {
    border-radius: 50%;
  }

  #userdata {
    top: -80px;
  }

  div {
    display: inline-block;
    position: relative;
  }

  #colorize {
    position: absolute;
    bottom: 10px;
    right: 10px;
  }

  #toggle {
    top: -60px;
  }

</style>
<svg class="chart"></svg>
<div class="row">
  <div class="col-sm-4">
    <h3>Enter your desired colors in hexadecimal value</h3>
    <textarea rows="6" cols="60" id="colorInput"></textarea>
    <button id="colorize" onclick="colorize()">Colorize</button>
  </div>
  <div class="col-sm-4" id="userdata">
    <h3>Enter your data</h3>
    <input type="text" id="name" placeholder="name">
    <input type="number" id="value" placeholder="value">
    <button onclick="addData()">Submit</button>
  </div>
  <div class="col-sm-4" id="toggle">
    <h3>Toggle Data Label</h3>
    <label class="switch">
            <input type="checkbox" onclick="togglePressed()" checked>
            <span class="slider round"></span>
        </label>
  </div>
</div>
<script src="https://d3js.org/d3.v3.js"></script>
<script src="d3legend.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
  var jsdata = [{
      name: "Locke",
      value: 4
    },
    {
      name: "Reyes",
      value: 8
    },
    {
      name: "Ford",
      value: 15
    },
    {
      name: "Jarrah",
      value: 16
    },
    {
      name: "Shephard",
      value: 23
    },
    {
      name: "Kwon",
      value: 52
    }
  ];

  console.log(typeof jsdata);
  var colorCodes = ["#6b486b", "#a05d56", "#d0743c", "#ff8c00"];
  var color = d3.scale.ordinal().range(colorCodes);
  //Set the margins for the bar chart. 
  var margin = {
      top: 20,
      right: 30,
      bottom: 30,
      left: 40
    },
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

  //Encoding ordinal data. rangeRoundBands is used to snap each position to the exact pixel boundary for crisp edges
  var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

  var y = d3.scale.linear()
    .range([height, 0]);

  var tooltip = d3.select("body").append("div").attr("class", "toolTip");
  //Adding the axes
  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

  //Declaring the chart container
  var chart = d3.select(".chart")
    .attr("width", width + margin.left + margin.right)
    .data(jsdata)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");



  x.domain(jsdata.map(function(jsdata) {
    return jsdata.name;
  }));
  y.domain([0, d3.max(jsdata, function(jsdata) {
    return jsdata.value;
  })]);

  chart.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

  chart.append("g")
    .attr("class", "y axis")
    .call(yAxis);

  chart.selectAll(".bar")
    .data(jsdata) // Using the data join pattern
    .enter().append("rect") //Selecting the chart container then append the width and height for new nodes
    .style("fill", function(jsdata, i) {
      return color(i);
    })
    .style("color", function() {
      return '#FFFFFF';
    })
    .on("mousemove", function(jsdata) {
      tooltip
        .style("left", d3.event.pageX - 50 + "px")
        .style("top", d3.event.pageY - 70 + "px")
        .style("display", "inline-block")
        .html((jsdata.name) + "<br>" + "£" + (jsdata.value));
    })
    .on("mouseout", function(jsdata) {
      tooltip.style("display", "none");
    })
    .attr("class", "bar")
    .attr("data-legend", function(jsdata) {
      return jsdata.name
    })
    .attr("x", function(jsdata) {
      return x(jsdata.name);
    })
    .attr("y", function(jsdata) {
      return y(jsdata.value);
    })
    .attr("height", function(jsdata) {
      return height - y(jsdata.value);
    })
    .attr("width", x.rangeBand());

  chart.selectAll(".text")
    .data(jsdata)
    .enter()
    .append("text")
    .attr("class", "label")
    .attr("x", (function(jsdata) {
      return x(jsdata.name) + 56;
    }))
    .attr("y", function(jsdata) {
      return y(jsdata.value) - 20;
    })
    .attr("dy", ".75em")
    .text(function(jsdata) {
      return jsdata.value;
    });

  /*chart.selectAll("text")
      .data(jsdata)
      .enter()
      .append("text")
      .text(function (jsdata) {
          return jsdata.value;
      })*/

  //Converting the column from name to integer
  function type(jsdata) {
    jsdata.value = +jsdata.value;
    return jsdata;
  }

  function togglePressed() {
    $(".label").toggle();
  }

  function colorize() {
    var lines = $('#colorInput').val().split('\n');
    for (var i = 0; i < lines.length; i++) {
      if (colorCodes.includes(lines[i])) {
        alert("Error. This color already exists.");
      } else {

        colorCodes.push(lines[i]);
      }
    }

    chart.selectAll(".bar")
      .style('fill', function(jsdata, i) {
        return color(i);
      })
      .attr("height", function(jsdata) {
        return height - y(jsdata.value);
      })
      .attr("width", x.rangeBand());


  }

  function addData() {
    var name = document.getElementById("name").value;
    var value = document.getElementById("value").value;

    var person = new Object();
    person.name = name;
    person.value = parseInt(value);

    jsdata.push(person);
    //chart.select(x).remove();
    x.domain(jsdata.map(function(jsdata) {
      return jsdata.name;
    }));
    y.domain([0, d3.max(jsdata, function(jsdata) {
      return jsdata.value;
    })]);

    chart.select(".xaxis").remove();

    chart.select(".x.axis")
      .call(xAxis);

    chart.select(".y.axis")
      .call(yAxis);


    var bars = chart.selectAll(".bar").data(jsdata);
    bars.enter().append("rect")
      .style("fill", function(jsdata, i) {
        return color(i);
      })
      .style("color", function() {
        return '#FFFFFF';
      })
      .on("mousemove", function(jsdata) {
        tooltip
          .style("left", d3.event.pageX - 50 + "px")
          .style("top", d3.event.pageY - 70 + "px")
          .style("display", "inline-block")
          .html((jsdata.name) + "<br>" + "£" + (jsdata.value));
      })
      .on("mouseout", function(jsdata) {
        tooltip.style("display", "none");
      })
      .attr("class", "bar")
      .attr("data-legend", function(jsdata) {
        return jsdata.name
      });
    bars.attr("x", function(jsdata) {
        return x(jsdata.name);
      })
      .attr("y", function(jsdata) {
        return y(jsdata.value);
      })
      .attr("height", function(jsdata) {
        return height - y(jsdata.value);
      })
      .attr("width", x.rangeBand());

    var texts = chart.selectAll(".label")
      .data(jsdata);

    texts.enter()
      .append("text")
      .attr("class", "label");

    texts.attr("x", (function(jsdata) {
        return x(jsdata.name) + 56;
      }))
      .attr("y", (function(jsdata) {
        return y(jsdata.value) - 20;
      }))
      .attr("dy", ".75em")
      .text(function(jsdata) {
        return jsdata.value;
      });

    /*chart.select("text")
        .data(jsdata)
        .enter()
        .append("text")
        .text(function (jsdata) {
            return jsdata.value;
        })*/

    bars.exit().remove();

    texts.exit().remove();


  }
  var legend = chart.append("g")
    .attr("class", "legend")
    .attr("transform", "translate(50,30)")
    .attr("data-legend-pos", "bottom")
    .style("font-size", "12px")
    .call(d3.legend);

</script>

PS:我在代码段中禁用了控制台,因为这里有很多错误。我建议你解决它们。


推荐阅读