d3.js用多线图刷

时间:2014-12-02 03:21:08

标签: d3.js brush

我正在制作一个多线图并使用画笔选择时间段。它广泛基于迈克博斯托克在http://bl.ocks.org/mbostock/1667367

的例子

我的图表位于http://lowercasen.com/dev/d3/general/piezobrush.html

我的问题是在我的'焦点'区域选择多行以应用画笔。我已根据键嵌套数据,因此数据在函数内。因为调用我的画笔的函数在该函数之外,它无法访问数据而我得到一个TypeError:undefined不是一个对象(评估'data.length')

以下是嵌套数据的代码:

     dataNest.forEach(function(d, i) {

       focus.append("path")
           .attr("class", "line")
                 .attr("id", d.key.replace(/\s+/g, ''))  //the replace stuff is getting rid of spaces
                 .attr("d", levelFocus(d.values)); 

       context.append("path")
            .attr("class", "line")
                 .attr("id", d.key.replace(/\s+/g, ''))  //the replace stuff is getting rid of spaces
                 .attr("d", levelContext(d.values)); 

在底部我有刷子的功能:

     function brushed() {
       xFocus.domain(brush.empty() ? xContext.domain() : brush.extent());
       focus.selectAll(".line").attr("d", levelFocus(d.values));
       focus.select(".x.axis").call(xAxisFocus);
     }

它适用于x轴(如果我注释掉我试图选择线条的线条),但我不知道如何正确选择线条。

对于任何乱码语法或令人困惑的语言道歉,我的编码技巧充其量是基本的。

非常感谢任何帮助,我已经搜索了几个小时的解决方案。

以下是Lars要求的完整代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
            <meta charset="utf-8">
            <title>Multiline with brush</title>
    <script src="http://d3js.org/d3.v3.js"></script>
    <script src="d3/tooltip.js"></script>
        <link href="styles/evidentlySoCharts.css" rel="stylesheet">
        <meta name="viewport" content="initial-scale=1">   

    <style>

    svg {
      font: 10px sans-serif;
    }

    path { 
        stroke-width: 1;
        fill: none;
    }

    #Stream1, #Nebo1D {
        stroke: #009390;
    }

    #Stream1Legend, #Nebo1DLegend {
        fill: #009390;
    }

    #Stream2, #Nebo2D {
        stroke: #8dc63f;
    }

    #Stream2Legend, #Nebo2DLegend {
        fill: #8dc63f;
    }

    #Stream3, #Nebo1S {
        stroke: #132d46;
    }

    #Stream3Legend, #Nebo1SLegend {
        fill: #132d46;
    }

    #Stream4, #Nebo2S {
        stroke: #aaa813;
    }

    #Stream4Legend, #Nebo2SLegend {
        fill: #aaa813;
    }

    #Stream5, #Nebo3 {
        stroke: #619dd4;
    }

    #Stream5Legend, #Nebo3Legend {
        fill: #619dd4;
    }

    .pn1d, .pn2d {
      fill: none;
      clip-path: url(#clip);
    }

    .pn1d {
      stroke: #009390;
    }

    .pn2d {
      stroke: #1b4164;
    }

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

    .brush .extent {
      stroke: #fff;
      fill-opacity: .125;
      shape-rendering: crispEdges;
    }

    </style>
        </head>



    <body>
    <script>

    var marginFocus = {top: 10, right: 10, bottom: 250, left: 40},
        marginContext = {top: 430, right: 10, bottom: 170, left: 40},
        width = 960 - marginFocus.left - marginFocus.right,
        heightFocus = 650 - marginFocus.top - marginFocus.bottom,
        heightContext = 650 - marginContext.top - marginContext.bottom;
        legendOffset = 550;

    var parseDate = d3.time.format("%d/%m/%y %H:%M").parse;

    var xFocus = d3.time.scale().range([0, width]),
        xContext = d3.time.scale().range([0, width]),
        yFocus = d3.scale.linear().range([heightFocus, 0]),
        yContext = d3.scale.linear().range([heightContext, 0]);

    var xAxisFocus = d3.svg.axis().scale(xFocus).orient("bottom"),
        xAxisContext = d3.svg.axis().scale(xContext).orient("bottom"),
        yAxisFocus = d3.svg.axis().scale(yFocus).orient("left");

    var levelFocus = d3.svg.line()
        .interpolate("linear")
        .x(function(d) { return xFocus(d.date); })
        .y(function(d) { return yFocus(d.level); });


    var levelContext = d3.svg.line()
        .interpolate("linear")
        .x(function(d) { return xContext(d.date); })
        .y(function(d) { return yContext(d.level); });

    var svg = d3.select("body").append("svg")
        .attr("width", width + marginFocus.left + marginFocus.right)
        .attr("height", heightFocus + marginFocus.top + marginFocus.bottom);

    svg.append("defs").append("clipPath")
        .attr("id", "clip")
      .append("rect")
        .attr("width", width)
        .attr("height", heightFocus);

    var focus = svg.append("g")
        .attr("class", "focus")
        .attr("transform", "translate(" + marginFocus.left + "," + marginFocus.top + ")");

    var context = svg.append("g")
        .attr("class", "context")
        .attr("transform", "translate(" + marginContext.left + "," + marginContext.top + ")");

    d3.csv("data/PiezoNeboNestSimple.csv", function(error, data) {
        data.forEach(function(d) {
        d.date = parseDate(d.date);
        d.level = +d.level;
        });

      xFocus.domain(d3.extent(data.map(function(d) { return d.date; })));
      yFocus.domain([d3.min(data.map(function(d) { return d.level; })) -2,0]);
      xContext.domain(xFocus.domain());
      yContext.domain(yFocus.domain());

        // Nest the entries by piezo
        var dataNest = d3.nest()
            .key(function(d) {return d.piezo;})
            .entries(data);

        legendSpace = width/dataNest.length; // spacing for legend // ******

    var brush = d3.svg.brush()
        .x(xContext)
        .on("brush", brushed);


    focus.selectAll("g").data(dataNest)
        .enter()
        .append("g")
        .attr("class", "line")
        .attr("id", function(d) { return d.key.replace(/\s+/g, '') })  //the replace stuff is getting rid of spaces
        .append("path")
        .attr("d", function(d) { return levelFocus(d.values); });    

    context.selectAll("g").data(dataNest)
        .enter()
        .append("g")
        .attr("class", "line")
        .attr("id", function(d) { return d.key.replace(/\s+/g, '') })  //the replace stuff is getting rid of spaces
        .append("path")
        .attr("d", function(d) { return levelContext(d.values); });    


      focus.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + heightFocus + ")")
          .call(xAxisFocus);

      focus.append("g")
          .attr("class", "y axis")
          .call(yAxisFocus);

      context.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + heightContext + ")")
          .call(xAxisContext);

      context.append("g")
          .attr("class", "x brush")
          .call(brush)
        .selectAll("rect")
          .attr("y", -6)
          .attr("height", heightContext + 7);

    function brushed() {
      xFocus.domain(brush.empty() ? xContext.domain() : brush.extent());
      focus.selectAll(".line").attr("d", levelFocus(dataNest.values));
      focus.select(".x.axis").call(xAxisFocus);
    }

    });


    </script>
    </body>
    </html>

1 个答案:

答案 0 :(得分:1)

就我所见,它主要归结为两件事。首先,您选择要更新的元素是g而不是path元素,其次,您需要引用绑定到元素的数据才能设置{{1} }。两者都很容易修复,d函数看起来像这样。

brushed

完整演示here。请注意,某些位仍然缺失,特别是用于将线条限制到图表区域的剪辑路径。这可以直接从您引用的示例中复制和粘贴。