D3.js 如何在多行D3图形中引用特定路径的值?

D3.js 如何在多行D3图形中引用特定路径的值?,d3.js,D3.js,我正在用多行填充一个图形,并尝试访问最高值,然后每隔几秒钟递增一次。我不确定使用什么语法来分别访问每一行 index.html: function generateVisualization(data){ //className for first timeline var className = "ch1Class"; data.forEach(function(d) { d.date = parseDate(d.date); d.price = +d.pric

我正在用多行填充一个图形,并尝试访问最高值,然后每隔几秒钟递增一次。我不确定使用什么语法来分别访问每一行

index.html:

function generateVisualization(data){

  //className for first timeline
  var className = "ch1Class";

  data.forEach(function(d) {
    d.date = parseDate(d.date);
    d.price = +d.price; // +  ensures its an integer
  });

  maxY = d3.max(data.map(function(d) { return d.price; }));
  obj[className] = maxY;
  maxX = d3.max(data.map(function(d) { return d.date; }));
  objD[className] = maxX;

  x.domain(d3.extent(data.map(function(d) { return Math.max(d.date); })));
  y.domain([0, d3.max(data.map(function(d) { return Math.max(d.price); }))]);
  x2.domain(x.domain());
  y2.domain(y.domain());

  focus.append("path")
      .datum(data)
      .attr("clip-path", "url(#clip)")
      .attr("d", area)
      .attr("class", className);

  //make sure the first textbox is selected in the channel selection

  $("#demo_box_1").attr("checked","checked");

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

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

  context.append("path")
      .datum(data)
      .attr("class", className)
      .attr("d", area2);

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

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

}


<!-- time series start -->
var margin = {top: 10, right: 10, bottom: 100, left: 40},
    margin2 = {top: 430, right: 10, bottom: 20, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    height2 = 500 - margin2.top - margin2.bottom;

var parseDate = d3.time.format("%b %Y").parse;

//var parseDate = d3.time.format("%x %X.%L").parse;

var x = d3.time.scale().range([0, width]),
    x2 = d3.time.scale().range([0, width]),
    y = d3.scale.linear().range([height, 0]),
    y2 = d3.scale.linear().range([height2, 0]);

var xAxis = d3.svg.axis().scale(x).orient("bottom"),
    xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
    yAxis = d3.svg.axis().scale(y).orient("left");

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

var area = d3.svg.area()
    .interpolate("monotone")//smooths path corners
    .x(function(d) { return x(d.date); })
    .y0(height)
    .y1(function(d) { return y(d.price); });

var area2 = d3.svg.area()
    .interpolate("monotone")//smooths path corners
    .x(function(d) { return x2(d.date); })
    .y0(height2)
    .y1(function(d) { return y2(d.price); });

var svg = d3.select("#maincontent1").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .attr("class", "timeLine");

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

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

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

var dataset;  //global variable

d3.csv("ch1.csv", function(error, data) {

  dataset = data;
  generateVisualization(data);

});

<!-- time series end -->
</script>

</div><!-- end #maincontent -->

您正在导入多个csv文件(格式为日期、价格),还是可以/正在导入一个文件,该文件具有针对单个日期行(日期、价格1、价格2、价格3)分配的多个值。如果您可以使用后者,那么您应该能够使用d.price 1、d.price 2等来选择最大值,就像您在代码中已经使用d.price一样。或者,您也可以在加载之前在php中组合数据,以便将所有数据作为单个文件加载(尽管我认为这不是您最喜欢的选项)。如果我能提出建议的话,下一篇评论中还有更多内容。将代码解析为最简单的在线版本,并将其发布到github/gist中。真的把额外的好东西都删掉了(感谢试用页面的离线链接,看起来很棒),这样问题就很明显了,然后对我来说可能更有意义。很抱歉,我想我还没有完全理解这个问题。谢谢你抽出时间。我将努力得到一个简化的要点版本。我的方法可能是将每个csv导入的结果存储在单独的全局对象中,这样它们就不会终止,我可以继续引用它们。我使用generateVisualization()函数中的第一个csv来执行此操作。但我猜这是不恰当的内存占用。。。这只是一个演示,所以我可以摆脱一些管道胶带解决方案:)太好了!好的选择。虽然我确信数据操作可以在d3中完成,但在服务器端用php脚本或类似脚本来完成可能会更好?不管是哪种方式,为了演示,管道胶带将足够,直到一个更优雅的解决方案抬头:-)。
//create an object to track max y values
var obj = {};
var objD = {};


// if adding/removing paths check max values and rescale if necessary
function maxValue(maxY,maxX,addRemove,className){

    //if adding and its not in the array yet, then add to array, then check to see if its got the highest yvalue, if so updateaxis
    if(addRemove=="add"){
        if((className in obj )!=true){
            // add new class/max value to an object
            obj[className] = maxY;
            objD[className] = maxY;
            //check to see if its the highest yvalue in the object and if so, rescale
            var max = 0;
            for(var i in obj){
                if(obj[i] > max) {
                  max = obj[i];
               }
            }
            if (max==obj[className]){
                updateAxis("y");
                //reScaleEverything();
            }
            // important, reset the y domain to the new max, if you don't do this then the brushing will use the last added paths y max
            y.domain([0, max]);
        } 
    }  else if (addRemove=="remove"){

        //if its being remove then it should already have a matching obj, remove it from the obj array and then test for the new max yVal, rescale to new max
        if((className in obj )==true){
            var max = 0;
            for(var i in obj){
                if(obj[i] > max) {
                  max = obj[i];
               }
            }
            if (max==obj[className]){
                delete obj[className];
                delete objD[className];

                var max = 0;
                for(var i in obj){
                    if(obj[i] > max) {
                      max = obj[i];
                   }
                }
                //set the new y domain
                y.domain([0, max]);
                //y2.domain([0, max]);

                //rescale y using the new max value
                updateAxis("y");
            }
        }
    }


}

// found in maxValue(), this is called after setting domains
function updateAxis(axisXY){
    if (axisXY == 'x'){//Update x-axis
    svg.select(".x.axis")
        .transition()
        .duration(1000)
        .call(xAxis);
    } else if (axisXY == 'y'){
    //Update y-axis
    svg.select(".y.axis")
        .transition()
        .duration(1000)
        .call(yAxis);
    }

    // very important, rescales all existing paths to new y values
    focus.selectAll("path").attr("d", area);
    //focus.selectAll("path").attr("d", area2);

    //focus.select(".x.axis").call(xAxis);
}

function rescaleEverything(){


}

function checkSetY(maxY){
    var max = 0;
    for(var i in obj){
        if(obj[i] > max) {
          max = obj[i];
       }
    }
    if(maxY>max){
        //if the new maxY is bigger then any other Y then set a new domain
        return y.domain([0, maxY]);
    }
}
function checkSetX(maxX){
    console.log(maxX);
    var max = 0;
    for(var i in objD){
        if(objD[i] > max) {
          max = objD[i];
       }
    }
    if(maxX>max){
        //if the new maxX is bigger then any other Y then set a new domain
        return x.domain([0, maxX]);
    }
}

function addCSV(csvFileName, className){

  d3.csv(csvFileName, function(error, data) { 

          data.forEach(function(d) {
            d.date = parseDate(d.date);
            d.price = +d.price;
          });

          maxY = d3.max(data.map(function(d) { return d.price; }));
          checkSetY(maxY);
          maxX = d3.max(data.map(function(d) { return d.date; }));
          checkSetX(maxX);
          //x.domain(d3.extent(data.map(function(d) { return d.date; })));
          //y.domain([0, d3.max(data.map(function(d) { return d.price; }))]);

          x2.domain(x.domain());
          y2.domain(y.domain());

          focus.append("path")
              .datum(data)
              .attr("clip-path", "url(#clip)")
              .attr("d", area)
              .attr("class", className);

          context.append("path")
              .datum(data)
              .attr("class", className)
              .attr("d", area2);

          // important, this fixes brushing issues, avoids multiple context brush areas
          context.selectAll("g.x.brush").remove();

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

            maxValue(maxY,maxX,"add",className);
                //maxX = d3.max(data.map(function(d) { return Date.max(d.date); }));
            //console.log(maxX);


        });
}

function removeCSV(className){
    var classRemoval = "." + className;
    d3.selectAll(classRemoval).transition().remove();
    maxValue(maxY,maxX,"remove",className);
}

function brushed() {
  x.domain(brush.empty() ? x2.domain() : brush.extent());
  //console.log(x2);
  focus.selectAll("path").attr("d", area);
  focus.select(".x.axis").call(xAxis); 
}

function incrementDate(){

    //pass in last date

}

$(document).ready(function() {

//addCSV("sp501.csv", "timeLine2");

    //toggle the side panel sliding
    $(".togglePanel").click(function(){
        //$("#channels").animate({left:'-130px'},350);
        var $lefty = $("#channels");
        $lefty.animate({
          left: parseInt($lefty.css('left'),10) == 0 ?
            -$lefty.outerWidth() :
            0
        });
    });

    $("#maincontent2, #maincontent3").hide();

    $(".gauge").hover(
        function(){
            var idName = $(this).attr('id');
            var newName = "." + idName.substring(0,3) + "Class";
            //alert(newName);
            $(newName).css("fill","#c2c2c2");
            $(newName).css("fill-opacity",".7");
            //$(newName).css("stroke-width","3");
        }, 
        function(){
            var idName = $(this).attr('id');
            var newName = "." + idName.substring(0,3) + "Class";
            $(newName).css("fill","none");
            $(newName).css("stroke-width","1");
        }
    );

    //hide all gauges
    $(".gauge").hide();
    //this one starts already open
    $("#ch1GaugeContainer").slideDown();

    $("#tabs li").click(function() {
        $("#tabs li").removeClass("selected");
        $(this).addClass("selected");
    });

    $('#channelSelect :checkbox').click(function() {
    var $this = $(this);
    var channelName = $this.attr("value") + ".csv"; 
    var className = $this.attr("value") + "Class";
    var guageName = "#" + $this.attr("value") + "GaugeContainer";
    // $this will contain a reference to the checkbox   
    if ($this.is(':checked')) {
        addCSV(channelName,className);
        $(guageName).slideDown();
    } else {
        removeCSV(className);
        $(guageName).slideUp();
    }

});


});