2014-12-02 2 views
1

Я делаю многострочный график и используя кисть для выбора периодов времени. Он широко основан на примере Майка Босток по адресу http://bl.ocks.org/mbostock/1667367d3.js кисть с многострочной диаграммой

Мой график на 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); 
    } 

Он отлично работает на оси х (если я закомментировать строку, в которой я пытаюсь выбрать строки), но я не знаю, как правильно выбрать строки.

Извинения за любой искаженный синтаксис или запутанный язык, мои навыки кодирования в лучшем случае являются основными.

Любая помощь очень признательна, я искал часы для решения.

Вот полный код по просьбе 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> 
+0

Не могли бы вы определить функцию «brushed» в той же области, что и «данные»? –

+0

Ларс, я пробовал свой неопытный путь, но безуспешно. Я почти уверен, что им нужно как-то оказаться в той же области, но мне не хватает навыков. Имейте в виду, что другие примеры (с одной строкой или областью, а не моими несколькими) определяют ее за пределами области данных. Тем не менее, я думаю, вы на правильном пути. Можете ли вы дать мне представление о том, как это сделать? – tgerard

+0

@LarsKotthoff Я обновил его, чтобы иметь чистую функцию в той же области, что и данные, но все же без радости. Проблема заключается в этой строке «focus.selectAll («. Line »). Attr (« d », levelFocus (d.values)); и ошибка, которую я получаю, заключается в том, что она не может найти переменную d. В принципе, я не знаю, как ссылаться на строки, которые я добавил в диаграмму. – tgerard

ответ

1

Это в основном сводится к двум вещам, насколько я могу видеть. Во-первых, элементы, которые вы выбираете для обновления, - это g, а не элементы path, а во-вторых, вам нужно ссылаться на данные, привязанные к элементам, чтобы установить d. Оба они легко фиксируются, и функция brushed выглядит примерно так.

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

Полная демо-версия here. Обратите внимание, что некоторые биты все еще отсутствуют, в частности путь клипа для ограничения строк в области диаграммы. Это можно скопировать и вставить прямо из примера, на который вы ссылались.

Смежные вопросы