1

我正在使用 Bootstrap、PHP、MySQL 和 d3.js 为当地非营利组织开发交互式学校成绩单。

一旦用户选择了学校(当用户提交学校选择表格时,屏幕上会呈现 3 个单独的条形图),我就可以毫无问题地渲染 d3 图表(示例)。为此,我执行查询,将它们编码为 PHP/MySQL 中的 JSON,然后使用 PHP 包含函数(在三个不同的场合)引用 3 个单独的 JavaScript 文件,这些文件包含呈现图表的 d3 代码。d3 为填充图表而引入的数据的引用嵌套在每个 JavaScript 文件中的 PHP 标记内。同样,这里没有问题,图表准确地呈现在它们应该呈现的位置并且它们看起来不错。

问题是我希望用户能够更改其中一个图表上的选项,然后在单击该表单中的按钮时使用新数据重新呈现该图表。

最初呈现的图表之一是来自所选学校的州标准化考试的四年级数学考试成绩数据。我希望用户能够查看四年级的其他测试科目(英语、科学和社会研究);此外,同样的 4 个科目在 3 年级和 5 – 8 年级进行测试。其他测试和科目的这些选项出现在 2 个选择框中,这些选择框出现在位于测试分数图 div 上方的 div 中的表单中。

我在更改事件处理程序(原始 JavaScript)上使用 Ajax 来触发 MySQL 查询,其中包含所选选项(主题和年级;学校从包含当前所选学校的学校 ID 的隐藏表单元素中提取)每次用户的主题/grade 等级选择改变。然后将来自最后一个查询的 JSON 写入另一个元素的值中,该元素以与主题/年级选择框相同的形式出现。表单的 PHP/html(我在下面的代码中只使用了一个更改处理程序):

echo "<form name='testselect' method=get>";
echo "<table>
    <tbody>
        <tr>
            <td>";
                echo "<select name='testtype' id='ttype' onChange='javascript:ajaxFunction();'>";       
                $dboxquery1 = "SELECT distinct subject FROM leapfile2012 WHERE site_code='$_POST[school]' ORDER BY subject;";
                $resultdbq1 = mysql_query($dboxquery1,$con) or die("SQL Error 1: " . mysql_error());    
                while($dbqr1 = mysql_fetch_array($resultdbq1))
                    {       
                    echo '<option value="'. $dbqr1['subject'] . '">' . $testType[$dbqr1['subject']] . '</option>';
                    }
                echo "</select>";
            echo "</td>
            <td>";
        echo "<select name='testsub' id='tsub'>";
            echo "<option value='ELA' selected='selected'>English</option>";
        echo "</select>";
            echo "</td>";
            echo "<td>" . "<input type='hidden' name='hidden' id='hidename' value='" . $_POST['school'] . "'></input></td>";
            echo" <td>";
                echo '<input type="button" id="data-submit" value="Get" onClick="javascript:doofus();"></input>';
            echo "</td>
                   <td>
                     <input type='hidden' name='hidden2' id='hidename2' value=''></input>
                   </td>                                
        </tr>
    </tbody>
</table>";              
echo '</form>';

点击事件(用户在科目/年级级别表单中单击“获取”)然后触发 d3 代码,该代码应该使用新选择的年级和科目的测试数据重新填充图表。该新/更新图形的 JSON 是从第二个隐藏元素的值中提取的。这就是一切都崩溃的地方,运行以下 JavaScript/d3 时出现错误:

function doofus() {
    var birdmanbirdman = document.getElementById('hidename2').value;
    var whutitdo = birdmanbirdman.length;
    var quote_be_gone = birdmanbirdman.substring(0,whutitdo);
    //var i_hope_this_works = new Array(quote_be_gone);
    //alert(i_hope_this_works);
    //alert(typeof(i_hope_this_works));
    //alert(typeof(birdmanbirdman));

var margin = {top: 35, right: 105, bottom: 30, left: 40},
    width = 370 - margin.left - margin.right,
    height = 289 - margin.top - margin.bottom;

    var data = new Array(quote_be_gone);

//var dontwant = ["site_name","site_code","subject","testsub"];

var formatAsPercentage = d3.format(".1%");

var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

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

var color = d3.scale.ordinal()
    .range(["#3366cc", "#dc3912", "#ff9900", "#109618", "#990099"]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickSize(1);

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left")
    .tickFormat(d3.format(".0%"))
    .tickSize(1);

var svg = d3.select("#area3").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 + ")");

 color.domain(d3.keys(data[0]).filter(function(key)
    { return key !== "year"; }));

  data.forEach(function(d) {
    var y0 = 0;
    d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
    d.total = d.ages[d.ages.length - 1].y1;
  });

   x.domain(data.map(function(d) { return d.year; }));
  y.domain([0, d3.max(data, function(d) { return d.total; })]);

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

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .attr("font-size", "1.0em")
      .style("text-anchor", "end")
      /*.text("Population")*/;

  var state = svg.selectAll(".state")
      .data(data)
    .enter().append("g")
      .attr("class", "g")
      .attr("transform", function(d) { return "translate(" + x(d.year) + ",0)"; });

  state.selectAll("rect")
      .data(function(d) { return d.ages; })
    .enter().append("rect")
      .attr("width", x.rangeBand())
      .attr("y", function(d) { return y(d.y1); })
      .attr("stroke","black")
      .attr("stroke-width",0.5)
      .attr("height", function(d) { return y(d.y0) - y(d.y1); })
      .style("fill", function(d) { return color(d.name); });

  state.selectAll("text.one")
      .data(function(d) { return d.ages; })
    .enter().append("text")
      .attr("x", function(d,i) { return x.rangeBand()/2;})
      .attr("y", function(d) { /*if ((y(d.y0) - y(d.y1))>=0.05) */ return y(d.y1) + (y(d.y0) - y(d.y1))/2 + 6; })
      .text(function (d) { if ((y(d.y0) - y(d.y1))>=0.05) return formatAsPercentage(d.y1 - d.y0);})
      .attr("fill", "white")
      .attr("font-family", "sans-serif")
      .attr("font-weight", "normal")
      .attr("text-anchor", "middle")
      .attr("font-size", "0.9em");    

  var legend = svg.selectAll(".legend")
      .data(color.domain().slice().reverse())
    .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

  legend.append("rect")
      .attr("x", width + 6)
      .attr("width", 12)
      .attr("height", 12)
      .attr("stroke","black")
      .attr("stroke-width", 0.5)
      .style("fill", color);

  legend.append("text")
      .attr("x", width + 100)
      .attr("y", 5)
      .attr("dy", ".35em")
      .style("text-anchor", "end")
      .style("font-size", "9px")
      .text(function(d) { return d; });

  svg.append("text")
    .attr("x", (width / 2))             
    .attr("y", 0 - (margin.top / 2))
    .attr("text-anchor", "middle")  
    .style("font-size", "11px") 
    .style("font-weight", "normal")  
    /*.text(gtitle)*/;

}

当我在 Chrome 中检查时,我在这段代码周围得到“未捕获的类型错误:无法读取未定义的属性'长度'”。

  data.forEach(function(d) {
    var y0 = 0;
    d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
    d.total = d.ages[d.ages.length - 1].y1;
  });

在调试过程中,我能够提醒应该填充图表的 JSON。然后,我可以使用本机 JavaScript 函数(本机数据类型是字符串)去掉开头和结尾的引号,然后成功验证新数据确实是一个对象。点击脚本中的 d3 代码似乎无法识别我试图传入的新数据/对象。

我不确定此时该怎么做。我一直无法在网上找到一个平行的例子。

您能提供的任何帮助将不胜感激。原谅我的啰嗦,我想确保你们都详细了解我的问题。如果这是一个基本错误,请对我放轻松。我在三月份才开始使用 JavaScript,四月份开始使用 PHP,六周前才开始使用 d3。

4

0 回答 0