【问题标题】:Echo JSON in a d3.js chart在 d3.js 图表中回显 JSON
【发布时间】:2016-12-07 08:01:47
【问题描述】:

我有一个使用d3.js 创建的图表,如果您将鼠标悬停在月份上,则会找到每周得分。

小提琴链接到我在这里谈论的图表:https://jsfiddle.net/qp7L1hob/1/

我的数据库中还有一个表,我在其中维护员工每周的得分记录。您在这里看到的只是四个星期 -(第 1 周到第 4 周),但在我的数据库中,我记录了所有每个月的几个星期。这仅供参考。

桌分评分: 用户登录后,我只想显示该人的相关分数。假设 Rob 登录,他的第 1 周分数是 47,第 2 周是 44,第 3 周是 44,第 4 周是 43。

问题:我是来自SQL 服务器的Using php to extract json。在PHP 文件下面就是这样做的。

问题是我如何将JSON 放入d3.js 文件中,即上面的小提琴。

请帮忙。

json 文件(让我们将其命名为data.php):我知道我需要在上面的d3.js 文件中包含这个data.php。但不确定如何。

<?php
session_start();
$servername = "xxxxxxx";
$connectioninfo = array(
    'Database' => 'xxxxxx'
);
$conn = sqlsrv_connect($servername, $connectioninfo);

if ($conn) {
    echo 'connection established';
}
else {
    echo 'connection failure';
    die(print_r(sqlsrv_errors() , TRUE));
}

$q1 = "SELECT WeekNumber,pointsRewarded,EmployeeID FROM pointsBadgeTable WHERE EmployeeID = '" . $_SESSION['id'] . "' ";
$stmt = sqlsrv_query($conn, $q1);

if ($stmt == false) {
    echo 'error to retrieve info !! <br/>';
    die(print_r(sqlsrv_errors() , TRUE));
}

do {
    while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
        $result[] = $row;
    }
}

while (sqlsrv_next_result($stmt));
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn); //Close the connnectiokn first
echo json_encode($result); //You will get the encoded array variable

?>

【问题讨论】:

  • 运行第一个代码 sn -p 给出"Uncaught ReferenceError: $ is not defined"
  • 如果您想在您的 javascript 中包含 PHP,请确保您的脚本位于您的 PHP 文件中。如果您的 javascript 在不同的文件中,您可能希望使用 http 请求使用 $.ajax() 从您的 PHP 文件中请求您的数据。
  • @Kingsthor 看起来不错。但它在这里不起作用。无论如何,谢谢。
  • @MaximilianPeters 不幸的是没有。我在发布问题之前检查了它,因为它是 stackoverflow 中唯一与我的问题相关的问题。无论如何,谢谢。

标签: javascript php sql-server json d3.js


【解决方案1】:

1:返回 JSON

既然你希望你的数据回到json格式,那么记得在响应头中设置内容类型,以及删除成功连接echo,因为它会弄乱结果:

<?php
session_start();
$servername = "xxxxxxx";
$connectioninfo = array(
    'Database' => 'xxxxxx'
);
$conn = sqlsrv_connect($servername, $connectioninfo);
if (!$conn) {
    echo 'connection failure';
    die(print_r(sqlsrv_errors() , TRUE));
}

$q1 = "SELECT WeekNumber,pointsRewarded,EmployeeID FROM pointsBadgeTable WHERE EmployeeID = '" . $_SESSION['id'] . "' ";
$stmt = sqlsrv_query($conn, $q1);
if ($stmt == false) {
    echo 'error to retrieve info !! <br/>';
    die(print_r(sqlsrv_errors() , TRUE));
}
do {
    while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
        $result[] = $row;
    }
}
while (sqlsrv_next_result($stmt));
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn); //Close the connnectiokn first

//Set content type to json
header('Content-Type: application/json');

//Echo a json object to the browser
echo json_encode($result);
?>

我还建议使用PDO 连接到您的数据库。基本上是这样的:

<?php

session_start();

$db = new PDO("sqlsrv:Server=YouAddress;Database=YourDatabase", "Username", "Password");

$sql = "SELECT WeekNumber,pointsRewarded,EmployeeID FROM pointsBadgeTable WHERE EmployeeID = ':UserID'";

if($stmt = $db->prepare($sql)){

    //Bind the sessionID
    $stmt->bindParam('UserID', $_SESSION['id']);

    //Execute query
    $stmt->execute();

    //Fetch data
    $data = $stmt->fetch(PDO::FETCH_ASSOC);

    //Close cursor
    $stmt->closeCursor();

    //Set header type to json
    header("content-type:application/json");

    //Echo json encoded array
    echo json_encode($data);
}
?>

请注意,如果您想使用 PDO,您可能需要下载 Microsoft 服务器 PDO 驱动程序。

Microsoft 有一个演示页面 here,它解释了如何将 PDO 与 SQL Server 一起使用。

2:与服务器通信

您需要能够从您的 PHP 页面中获取数据。最好的方法是通过Ajax

您需要向data.php 文件发送一个Ajax 请求(为简单起见,使用jQuery 的.get()):

$.get("path/to/data.php", function(data){
  //`data` is the JSON that the server echoed 
});

或者,在原版 JS 中:

httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
  if (httpRequest.readyState === XMLHttpRequest.DONE) {
    if (httpRequest.status === 200) {
      var data = httpRequest.responseText;

      //Do stuff with data here
    } 
  }
};
httpRequest.open('GET', "path/to/data.php");
httpRequest.send();

3:使用数据

所以现在我们有来自服务器的数据,但它不是图表可用的格式,我们该怎么办?

根据您的 cmets,Ajax 请求以如下格式返回数据:

[{
    "WeekNumber": "week49",
    "pointsRewarded": 50,
    "EmployeeID": 100739
}, {
    "WeekNumber": "week51",
    "pointsRewarded": 50,
    "EmployeeID": 100739
}, {
    "WeekNumber": "week50",
    "pointsR‌​ewarded": 50,
    "EmployeeID": 100739
}]

但是,查看您的 JSFiddle,它需要采用完全不同的格式,因此很明显我们需要更改格式。

首先,我们需要解析对象,所以我们拥有所有正确的数据:

function ParseData(data) {

  var parsed = {};

  var months = ['January - 2016', 'February - 2016', 'March - 2016', 'April - 2016', 'May - 2016', 'June - 2016', 'July - 2016', 'August - 2016', 'September - 2016', 'October - 2016', 'November - 2016', 'December - 2016'];

  data.forEach(function(item) {
    var week = parseInt(item.WeekNumber.slice(4)),
      month = Math.floor((week - 1) / 4);

    if (!parsed[month]) parsed[month] = {
      weeks: [],
      points: 0,
      month: months[month - 1]
    }

    var weekLabel = "Week " + week + ": " + item.pointsRewarded;

    parsed[month].weeks.push(weekLabel);
    parsed[month].points += item.pointsRewarded;

  });

  return FormatData(parsed);
}

我们在这里所做的只是循环遍历结果,并使用相关信息构建一个对象。接下来,我们需要格式化数据,使其与图表一起使用。由于我们已经有了解析的数据,这很简单:

function FormatData(data) {

  var formatted = {
    points: [],
    weeks: [],
    months: []
  };

  for (var month in data) {

    var now = data[month];

    formatted.points.push(now.points);
    formatted.months.push(now.month);
    formatted.weeks.push(now.weeks.join("<br>"));
  }

  return formatted;
}

现在,当您致电 ParseData(ajaxData) 时,它会返回图表所需的所有信息。

A working demo can be seen here,带有虚假数据。

现在我们需要做的就是等待以正确的数据呈现图表。在这种情况下,我将图表的所有代码包装在它自己的函数中,并使其使用在formattedData 参数中传递给它的数据:

function InitChart(formattedData) {
  let colors = ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#e0e0e0', '#bababa', '#878787', '#4d4d4d', '#1a1a1a', 'white', 'white'];


  var width = document.querySelector('.chart-wrapper').offsetWidth,
    height = document.querySelector('.chart-wrapper').offsetHeight,
    minOfWH = Math.min(width, height) / 2,
    initialAnimDelay = 300,
    arcAnimDelay = 150,
    arcAnimDur = 3000,
    secDur = 1000,
    secIndividualdelay = 150;

  var radius = undefined;

  // calculate minimum of width and height to set chart radius
  if (minOfWH > 200) {
    radius = 200;
  } else {
    radius = minOfWH;
  }

  // append svg
  var svg = d3.select('.chart-wrapper').append('svg').attr({
    'width': width,
    'height': height,
    'class': 'pieChart'
  }).append('g');

  svg.attr({
    'transform': 'translate(' + width / 2 + ', ' + height / 2 + ')'
  });

  // for drawing slices
  var arc = d3.svg.arc().outerRadius(radius * 0.6).innerRadius(radius * 0.45);

  // for labels and polylines
  var outerArc = d3.svg.arc().innerRadius(radius * 0.85).outerRadius(radius * 0.85);

  // d3 color generator
  // let c10 = d3.scale.category10();

  var tooltip = d3.select("body").append("div").attr("class", "tooltip").style("opacity", 0);

  var pie = d3.layout.pie().value(function(d) {
    return d;
  }).sort(null);

  var draw = function draw() {

    svg.append("g").attr("class", "lines");
    svg.append("g").attr("class", "slices");
    svg.append("g").attr("class", "labels");

    // define slice
    var slice = svg.select('.slices').datum(formattedData.points).selectAll('path').data(pie);
    slice.enter().append('path').attr({
      'fill': function fill(d, i) {
        return colors[i];
      },
      'd': arc,
      'stroke-width': '25px'
    }).attr('transform', function(d, i) {
      return 'rotate(-180, 0, 0)';
    }).style('opacity', 0).transition().delay(function(d, i) {
      return i * arcAnimDelay + initialAnimDelay;
    }).duration(arcAnimDur).ease('elastic').style('opacity', 1).attr('transform', 'rotate(0,0,0)');

    slice.transition().delay(function(d, i) {
      return arcAnimDur + i * secIndividualdelay;
    }).duration(secDur).attr('stroke-width', '5px');

    var midAngle = function midAngle(d) {
      return d.startAngle + (d.endAngle - d.startAngle) / 2;
    };

    var text = svg.select(".labels").selectAll("text").data(pie(formattedData.points));

    text.enter().append('text').attr('dy', '0.35em').style("opacity", 0).attr("cursor", "default").style('fill', function(d, i) {
      return colors[i];
    }).text(function(d, i) {
      return formattedData.months[i];
    }).attr('transform', function(d) {
      // calculate outerArc centroid for 'this' slice
      var pos = outerArc.centroid(d);
      // define left and right alignment of text labels
      pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
      return 'translate(' + pos + ')';
    }).style('text-anchor', function(d) {
      return midAngle(d) < Math.PI ? "start" : "end";
    }).transition().delay(function(d, i) {
      return arcAnimDur + i * secIndividualdelay;
    }).duration(secDur).style('opacity', 1);

    text.on("mousemove", function(d, i) {
      tooltip.html(formattedData.weeks[i])
        .style('top', d3.event.pageY - 6 + 'px')
        .style('left', d3.event.pageX + 14 + 'px')
        .style("opacity", 1);
    }).on("mouseout", function(d) {
      tooltip.style("opacity", 0);
    });


    var polyline = svg.select(".lines").selectAll("polyline").data(pie(formattedData.points));

    polyline.enter().append("polyline").style("opacity", 0.5).attr('points', function(d) {
      var pos = outerArc.centroid(d);
      pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
      return [arc.centroid(d), arc.centroid(d), arc.centroid(d)];
    }).transition().duration(secDur).delay(function(d, i) {
      return arcAnimDur + i * secIndividualdelay;
    }).attr('points', function(d) {
      var pos = outerArc.centroid(d);
      pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
      return [arc.centroid(d), outerArc.centroid(d), pos];
    });
  };

  draw();

  var button = document.querySelector('button');

  var replay = function replay() {

    d3.selectAll('.slices').transition().ease('back').duration(500).delay(0).style('opacity', 0).attr('transform', 'translate(0, 250)').remove();
    d3.selectAll('.lines').transition().ease('back').duration(500).delay(100).style('opacity', 0).attr('transform', 'translate(0, 250)').remove();
    d3.selectAll('.labels').transition().ease('back').duration(500).delay(200).style('opacity', 0).attr('transform', 'translate(0, 250)').remove();

    setTimeout(draw, 800);
  };
}

现在,只需将它们放在一起并使用数据呈现图表:

$.get("path/to/data.php", function(data){
  //Get data
  var parsedData = ParseData(data);
  //Render chart
  InitChart(parsedData);
});

You can see the fully updated JS file here.

别忘了设置正确的 ajax URL。

【讨论】:

  • 感谢您的意见。我会按照您所说的进行尝试。我会回复您。
  • 但是如何将数据拉到上面小提琴的javascript中
  • @jane ajax 请求返回数据。
  • 谢谢。我会回复你的。
  • Jacob ,我猜它也应该在没有 PDO 的情况下工作。
猜你喜欢
  • 2023-04-02
  • 2019-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-10
  • 2013-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多