javascript - 尝试在不使用 GET 的情况下将 JSON 加载到 d3 TreeMap 中

标签 javascript json d3.js

我正在使用http://bost.ocks.org/mike/treemap/尝试将 D3 树形图合并到 Splunk 中。但是,它在 d3.JSON("flare.json") 上出错,因为它找不到该文件。我尝试将 JSON 数组直接放入 js 中并调用 root = JSON.parse(myjson),但随后它会使用意外字符 JSON.parse 进行数组。如果您查看 Bostick 页面中的 js,您会发现我不能只删除 d3.JSON,因为它会回调实际渲染树形图的函数。

您对如何解决这个问题有什么想法吗?

renderResults: function($super, results) {

    if(!results) {
    this.resultsContainer.html('No content available.');
        return;
    }
    var margin = {top: 20, right: 0, bottom: 0, left: 0},
        width = 960,
        height = 500 - margin.top - margin.bottom,
        formatNumber = d3.format(",d"),
        transitioning;

    var x = d3.scale.linear()
        .domain([0, width])
        .range([0, width]);

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

    var treemap = d3.layout.treemap()
        .children(function(d, depth) { return depth ? null : d._children; })
        .sort(function(a, b) { return a.value - b.value; })
        .ratio(height / width * 0.5 * (1 + Math.sqrt(5)))
        .round(false);

    var svg = d3.select("#chart").append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.bottom + margin.top)
        .style("margin-left", -margin.left + "px")
        .style("margin.right", -margin.right + "px")
      .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
        .style("shape-rendering", "crispEdges");

    var grandparent = svg.append("g")
        .attr("class", "grandparent");

    grandparent.append("rect")
        .attr("y", -margin.top)
        .attr("width", width)
        .attr("height", margin.top);

    grandparent.append("text")
        .attr("x", 6)
        .attr("y", 6 - margin.top)
        .attr("dy", ".75em");

    var myjson = not including the actual array to save space

            root = JSON.parse(myjson); 




    d3.json("flare.json", function(root) { 
      initialize(root);
      accumulate(root);
      layout(root);
      display(root); 

      function initialize(root) {
        root.x = root.y = 0;
        root.dx = width;
        root.dy = height;
        root.depth = 0;
      } 

      // Aggregate the values for internal nodes. This is normally done by the
      // treemap layout, but not here because of our custom implementation.
      // We also take a snapshot of the original children (_children) to avoid
      // the children being overwritten when when layout is computed.
      function accumulate(d) {
        return (d._children = d.children)
            ? d.value = d.children.reduce(function(p, v) { return p + accumulate(v); }, 0)
            : d.value;
      }

      // Compute the treemap layout recursively such that each group of siblings
      // uses the same size (1×1) rather than the dimensions of the parent cell.
      // This optimizes the layout for the current zoom state. Note that a wrapper
      // object is created for the parent node for each group of siblings so that
      // the parent’s dimensions are not discarded as we recurse. Since each group
      // of sibling was laid out in 1×1, we must rescale to fit using absolute
      // coordinates. This lets us use a viewport to zoom.
      function layout(d) {
        if (d._children) {
          treemap.nodes({_children: d._children});
          d._children.forEach(function(c) {
            c.x = d.x + c.x * d.dx;
            c.y = d.y + c.y * d.dy;
            c.dx *= d.dx;
            c.dy *= d.dy;
            c.parent = d;
            layout(c);
          });
        }
      }

      function display(d) {
        grandparent
            .datum(d.parent)
            .on("click", transition)
          .select("text")
            .text(name(d));

        var g1 = svg.insert("g", ".grandparent")
            .datum(d)
            .attr("class", "depth");

        var g = g1.selectAll("g")
            .data(d._children)
          .enter().append("g");

        g.filter(function(d) { return d._children; })
            .classed("children", true)
            .on("click", transition);

        g.selectAll(".child")
            .data(function(d) { return d._children || [d]; })
          .enter().append("rect")
            .attr("class", "child")
            .call(rect);

        g.append("rect")
            .attr("class", "parent")
            .call(rect)
          .append("title")
            .text(function(d) { return formatNumber(d.value); });

        g.append("text")
            .attr("dy", ".75em")
            .text(function(d) { return d.name; })
            .call(text);

        function transition(d) {
          if (transitioning || !d) return;
          transitioning = true;

          var g2 = display(d),
              t1 = g1.transition().duration(750),
              t2 = g2.transition().duration(750);

          // Update the domain only after entering new elements.
          x.domain([d.x, d.x + d.dx]);
          y.domain([d.y, d.y + d.dy]);

          // Enable anti-aliasing during the transition.
          svg.style("shape-rendering", null);

          // Draw child nodes on top of parent nodes.
          svg.selectAll(".depth").sort(function(a, b) { return a.depth - b.depth; });

          // Fade-in entering text.
          g2.selectAll("text").style("fill-opacity", 0);

          // Transition to the new view.
          t1.selectAll("text").call(text).style("fill-opacity", 0);
          t2.selectAll("text").call(text).style("fill-opacity", 1);
          t1.selectAll("rect").call(rect);
          t2.selectAll("rect").call(rect);

          // Remove the old node when the transition is finished.
          t1.remove().each("end", function() {
            svg.style("shape-rendering", "crispEdges");
            transitioning = false;
          });
        }

        return g;
      }

      function text(text) {
        text.attr("x", function(d) { return x(d.x) + 6; })
            .attr("y", function(d) { return y(d.y) + 6; });
      }

      function rect(rect) {
        rect.attr("x", function(d) { return x(d.x); })
            .attr("y", function(d) { return y(d.y); })
            .attr("width", function(d) { return x(d.x + d.dx) - x(d.x); })
            .attr("height", function(d) { return y(d.y + d.dy) - y(d.y); });
      }

      function name(d) {
        return d.parent
            ? name(d.parent) + "." + d.name
            : d.name;
      }
    };

} 

我仍然不能 100% 确定这两者如何进行交互。我有一点 JavaScript 经验,但没有 Python 经验。 Splunk 将所有这些脚本集成在一起的方式令人困惑。

import cherrypy
import controllers.module as module

import splunk, splunk.search, splunk.util, splunk.entity
import json
from splunk.appserver.mrsparkle.lib import jsonresponse
import lib.util as util
import lib.i18n as i18n

import logging
logger = logging.getLogger('splunk.module.TreeMap1')

import math
import cgi

class TreeMap1(module.ModuleHandler):

def generateResults(self, host_app, client_app, sid, count=1000, 
        offset=0, entity_name='results'):

    count = max(int(count), 0)
    offset = max(int(offset), 0)
    if not sid:
        raise Exception('TreeMap1.generateResults - sid not passed!')

    try:
        job = splunk.search.getJob(sid)
    except splunk.ResourceNotFound, e:
        logger.error('TreeMap could not find job %s. Exception: %s' % (sid, e))
        return _('<p class="resultStatusMessage">Could not get search data.</p>')

    dataset = getattr(job, entity_name)[offset: offset+count]

    outputJSON = {}
    for i, result in enumerate(dataset):
        tdict = {}
        tdict[str(result.get('itemName', None))] = str(result.get('totalCPU', None))
        name = str(result.get('itemCat', None))
        if name not in outputJSON:
            outputJSON[name] = dict()
        outputJSON[name].update(tdict)

    cherrypy.response.headers['Content-Type'] = 'text/json'
    return json.dumps(outputJSON, sort_keys=True)

def render_json(self, response_data, set_mime='text/json'):
    cherrypy.response.headers['Content-Type'] = set_mime

    if isinstance(response_data, jsonresponse.JsonResponse):
        response = response_data.toJson().replace("</", "<\\/")
    else:
        response = json.dumps(response_data).replace("</", "<\\/")

    return ' ' * 256  + '\n' + response

最佳答案

D3 的 d3.JSON(url, ...) 从字面上执行 GET 请求并尝试将响应解析为 JSON*;它类似于 jQuery 的 $.getJSON(url, ...)。如果您已经拥有构建树形图所需的 JSON,则只需完全忽略该调用并直接进入回调。 如果你已经有一个数组/对象,则不需要JSON.parse; JSON.parse 将有效的 JSON 字符串转换为数组/对象。

*请参阅 d3.json 上的文档了解更多...

同样,如果您已经拥有数据,则可以使用:

  ...

  var myJSON = [ ... ] //The actual array you're loading.
  initialize(myJSON);
  accumulate(myJSON);
  layout(myJSON);
  display(myJSON);

  ... 

但是,请注意您在上面的代码中实际执行的操作。您正在将一个数组传递给initialize——它似乎需要一个对象:

  function initialize(root) { //Root in this case is myVar -- an ARRAY.
    root.x = root.y = 0;  //Arrays don't have fields. This is BAD.
    root.dx = width;
    root.dy = height;
    root.depth = 0;
  } 

因此,您应该做的是弄清楚 myJSON 应该使用什么类型的结构。

<小时/>

如果您要修复的错误实际上是找不到“flare.json”文件,那么您的问题实际上是服务器端。您如何提供flare.json 文件?尝试在浏览器中访问它,以确保它位于您认为的位置。

关于javascript - 尝试在不使用 GET 的情况下将 JSON 加载到 d3 TreeMap 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24764880/

相关文章:

javascript - 正确使用setTimeout

javascript - 广度优先遍历对象

javascript - d3v4 如何将条形图设置为不同的颜色

javascript - 如何控制D3 V4的缩放速度?

javascript - 动态加载的 CSS 在 Windows 8 应用程序中无效

javascript - 将 JSON 节点名称设置为变量值

javascript - ES5 Object.assign 等效项

c# - 如何使用反射通过引用传递参数

javascript - JavaScript 中 "intersect"两个 JSON 对象数组的公共(public)属性的最佳方法?

javascript - 为什么内部工具提示是 "Undefined"?