Javascript 如何在d3.js中绘制多条线,有3条限制线。这些值是从数据库中检索的

Javascript 如何在d3.js中绘制多条线,有3条限制线。这些值是从数据库中检索的,javascript,d3.js,line,Javascript,D3.js,Line,我有一个折线图,对折线的值进行计算,根据一些标准,平均值、上限和下限会发生变化。在图中,我有3条极限线,上下限和正常值线。现在,我能够通过上述代码完美地实现极限线 这里我循环,每次迭代我画3条限制线。但是现在我把极限值存储在一个数据库中,计算在一个diff文件中完成,并将极限值与主值一起存储在一个数据库中。如何从db中绘制这些线,以便这些线能够在画笔中使用,非常重要。db中的列值为日期、闭合值、平均值、上限、下限。 例如2013年2月21日,250、63.50、320、33.89 2013年2月

我有一个折线图,对折线的值进行计算,根据一些标准,平均值、上限和下限会发生变化。在图中,我有3条极限线,上下限和正常值线。现在,我能够通过上述代码完美地实现极限线

这里我循环,每次迭代我画3条限制线。但是现在我把极限值存储在一个数据库中,计算在一个diff文件中完成,并将极限值与主值一起存储在一个数据库中。如何从db中绘制这些线,以便这些线能够在画笔中使用,非常重要。db中的列值为日期、闭合值、平均值、上限、下限。 例如2013年2月21日,250、63.50、320、33.89 2013年2月22日,255,63.50320,33.89 2013年2月23日,192,63.50,320,33.89 2013年2月24日,90,45.50,120,23.9 2013年2月25日,67,45.50,120,23.9

首先我要画极限线,然后再画价值线。我正在将限制值转换为db,以减少客户端的计算量,主要是帮助实现笔刷滑块功能。 当它们的值发生变化时,我希望极限线断开,例如平均值从63.50到45.50,这两个值之间不能有线

正常值行代码与相同

我已经把3行放在一个组中,例如,但我不能在画笔中更新它作为另一个值行。下面给出了该图的代码。城市变量是一组由3个值组成的均值、下限和上限。如何更改每行的颜色。因为我使用了d3.scale.category10,所以我有预定义的颜色。我想要一个从一个值到另一个值的折线,在极限范围内,定义的行不通,我还能用别的方法吗

<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<style>
body { font: 14px Arial;}
svg {
  font: 10px sans-serif;
}
circle {
   -moz-transition: all 0.3s;
   -o-transition: all 0.3s;
   -webkit-transition: all 0.3s;
   transition: all 0.3s;
}           
circle:hover {
        stroke: orange; 
        stroke-width:2;
            }
path { 
    stroke: steelblue;
    stroke-width: 1;
    fill: none;
}



.axis path,
.axis line {
    fill: none;
    stroke: green;
    stroke-width: 1;
    shape-rendering: crispEdges;
}
div.tooltip {   
    position: absolute;         
    text-align: center;         
    width: auto;                    
    height: auto;                   
    padding: 2px;               
    font: 14px sans-serif;      
    background: lightsteelblue; 
    border: 0px;        
    border-radius: 8px;         
    pointer-events: none;
}
.icon {
    float: right;
    display: block;
    margin-bottom: 100;
    margin-left: 0;
    margin-right: 0;
    margin-top: 0;
    padding-bottom: 0;
    padding-left: 0;
    padding-right: 0;
    padding-top: 0;
}       

.download { 
  background: lightblue; 
  color: blue; 
  font-weight: 900; 
  border: 2px; 
  padding: 4px; 
  margin:4px;
}   
.brush .extent {
  stroke: #fff;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}   

</style>


</script>
</head>
<body>
<div id="svg"></div>
<button class="download" onClick="javascript:(function () { var e = document.createElement('script'); if (window.location.protocol === 'https:') { e.setAttribute('src', 'https://raw.github.com/NYTimes/svg-crowbar/gh-pages/svg-crowbar.js'); } else { e.setAttribute('src', 'http://nytimes.github.com/svg-crowbar/svg-crowbar.js'); } e.setAttribute('class', 'svg-crowbar'); document.body.appendChild(e); })();"> Download</button>

<script type="text/javascript" src="d3/d3.v3.js"></script>
<script>


var margin = {top: 10, right: 10, bottom: 100, left: 40},
    margin2 = {top: 430, right: 10, bottom: 30, left: 40},
        width = 2000 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom,
        height2 = 500 - margin2.top - margin2.bottom;


var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");

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


var color = d3.scale.category10();


var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");

var yAxis = d3.svg.axis().scale(y).orient("left");

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

var line = d3.svg.line()
    .interpolate("step")
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.limit); });

var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });

var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });

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

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

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



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

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


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







var arr=new Array();
// Get the data
d3.json("data/data3.php", function(error, data) { 

color.domain(d3.keys(data[0]).filter(function(key) {  if(key !== "date"&&key !== "close") return key; }));


    data.forEach(function(d,i) {




    d.date = parseDate(d.date);

        d.close = +d.close;
    d.mean=+d.mean;
    d.ucl=+d.ucl;
    d.lcl=+d.lcl;   

    arr[i]=d.close;


    len=i+1;


    });


var cities = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {date: d.date, limit: +d[name]};
      })
    };
  });






 var min=0;
var max=200;
// Scale the range of the data

    x.domain(d3.extent(data, function(d) { return d.date; }));

  //  y.domain([min-10, max+10]);
    //y.domain([0, d3.max(data, function(d) { return d.ucl; })]);

y.domain([
    d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.limit; }); }),
    d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.limit; }); })
  ]);

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


    //y.domain([lsl-5, d3.max(data, function(d) { return d.close; })]);


  var city= focus.selectAll(".city")
      .data(cities)
      .enter().append("g")
      .attr("class", "city");

    city.append("path")
      .attr("class", "line")
      .attr("d", function(d) { return line(d.values); })
      .style("stroke", function(d) { return color(d.name); });







   focus.append("path")     // Add the valueline path.
    .datum(data)
        .attr("class","valueline")
    .attr("d", valueline);

    focus.selectAll(".dot").data(data).enter().append("a").attr("class", "dot")
        .attr("xlink:href",function(d,i){if(d.close>=d.ucl||d.close<=d.lcl)return "http://en.wikipedia.org";})
    .append("circle")
        .attr("r", 2)
    .style("fill", function(d,i) {            // <== Add these
        if(d.close==0) {return "none"}              
        if(d.close>=d.ucl||d.close<=d.lcl) {return "red"}

            else    { return "steelblue" }          // <== Add these
        ;})  
        .attr("cx", function(d) { return x(d.date); })
        .attr("cy", function(d) { return y(d.close); })
    .on("mouseover", function(d,i) {

            div.transition()        
                .duration(200)      
                .style("opacity", .9);      
                div.html(function(){
    if(d.close==0)
    {return}
    if(d.close>=d.ucl)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " > UPPER LIMIT"}
    else if(d.close<=lcl)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " < LOWER LIMIT"}

    else {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b>"}
;})
                .style("left", (d3.event.pageX) + "px")     
                .style("top", (d3.event.pageY - 28) + "px");    
            })                  
        .on("mouseout", function(d) {       
            div.transition()        
                .duration(500)      
                .style("opacity", 0);
       }).style("pointer-events","visible");




    /*
city.append("text")
      .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
      .attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.limit) + ")"; })
      .attr("x", 3)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });

*/
            // Add the X Axis

    focus.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(xAxis)
    .selectAll("text")  
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", function(d) {
                return "rotate(-65)" 
                });


    focus.append("text")             // text label for the x axis
        .attr("x", width/2 )
        .attr("y",  height+margin.bottom)
        .style("text-anchor", "middle")
        .text("Date");  

// Add the Y Axis

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

    focus.append("text").attr("transform","rotate(-90)").attr("y", 0-margin.left+10 )
        .attr("x",0-( height/2) )
        .style("text-anchor", "middle")
    .style("text-decoration", "underline")  
        .text("issue"); 

    //title to graph
focus.append("text")
        .attr("x", (width / 2))             
        .attr("y", 0 - (margin.top / 2))
        .attr("text-anchor", "middle")  
        .style("font-size", "16px") 
        .style("text-decoration", "underline")  
        .text("Issue vs Date Graph");


context.append("path")      // Add the valueline path.
        .attr("d", valueline2(data));

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);



});


function brushed() {

  x.domain(brush.empty() ? x2.domain() : brush.extent());


  focus.selectAll(".valueline").attr("d",valueline);
  focus.selectAll(".dot").select("circle").attr("cx", function(d) { return x(d.date); });
  focus.selectAll(".city").attr("d",line);
  focus.select(".x.axis").call(xAxis);
}

function type(d) {
  d.date = parseDate(d.date);
  d.close = +d.close;
  d.ucl=+d.ucl;
  d.lcl=+d.lcl;
  d.mean=+d.mean;
  return d;
}




</script>

</body>
<html>

我应该如何在brushed中调用组线

您希望将数据放入数组类型结构的数组中,因此您可以将所有线绘制为一个d3选择,如中所示。然后,当画笔的比例发生变化时,您还可以使用相同的选择来更新所有线。要在值发生变化时使限制线断开,您需要:使用一个已定义的函数,如果某个点与上一个点的值不同,则该函数会使该点未定义,但随后会与缺失的点产生间隙,不只是一个中断,或者为每个部分将数组拆分为多个子数组,并为每个.P.S.绘制单独的线。您可能想查看该步骤,看看这是否可以作为打破界限的替代方案;这将使您的代码更简单!是否有一种方法可以根据值的唯一性将每个限制行生成一组行。所以对于eg来说,如果平均极限改变,它将是一条新的线。所以我不需要一个新的解决方案来解决这个问题。有没有一种方法,我可以使一组线和所有的更新在一个使用刷子。使用步长插值似乎不够可行。因为我想在limt值更改后完全中断。@AmeliaBR我更新了关于数组行数组的问题,你能检查一下吗
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<style>
body { font: 14px Arial;}
svg {
  font: 10px sans-serif;
}
circle {
   -moz-transition: all 0.3s;
   -o-transition: all 0.3s;
   -webkit-transition: all 0.3s;
   transition: all 0.3s;
}           
circle:hover {
        stroke: orange; 
        stroke-width:2;
            }
path { 
    stroke: steelblue;
    stroke-width: 1;
    fill: none;
}



.axis path,
.axis line {
    fill: none;
    stroke: green;
    stroke-width: 1;
    shape-rendering: crispEdges;
}
div.tooltip {   
    position: absolute;         
    text-align: center;         
    width: auto;                    
    height: auto;                   
    padding: 2px;               
    font: 14px sans-serif;      
    background: lightsteelblue; 
    border: 0px;        
    border-radius: 8px;         
    pointer-events: none;
}
.icon {
    float: right;
    display: block;
    margin-bottom: 100;
    margin-left: 0;
    margin-right: 0;
    margin-top: 0;
    padding-bottom: 0;
    padding-left: 0;
    padding-right: 0;
    padding-top: 0;
}       

.download { 
  background: lightblue; 
  color: blue; 
  font-weight: 900; 
  border: 2px; 
  padding: 4px; 
  margin:4px;
}   
.brush .extent {
  stroke: #fff;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}   

</style>


</script>
</head>
<body>
<div id="svg"></div>
<button class="download" onClick="javascript:(function () { var e = document.createElement('script'); if (window.location.protocol === 'https:') { e.setAttribute('src', 'https://raw.github.com/NYTimes/svg-crowbar/gh-pages/svg-crowbar.js'); } else { e.setAttribute('src', 'http://nytimes.github.com/svg-crowbar/svg-crowbar.js'); } e.setAttribute('class', 'svg-crowbar'); document.body.appendChild(e); })();"> Download</button>

<script type="text/javascript" src="d3/d3.v3.js"></script>
<script>


var margin = {top: 10, right: 10, bottom: 100, left: 40},
    margin2 = {top: 430, right: 10, bottom: 30, left: 40},
        width = 2000 - margin.left - margin.right,
        height = 500 - margin.top - margin.bottom,
        height2 = 500 - margin2.top - margin2.bottom;


var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");

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


var color = d3.scale.category10();


var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");

var yAxis = d3.svg.axis().scale(y).orient("left");

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

var line = d3.svg.line()
    .interpolate("step")
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.limit); });

var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });

var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });

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

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

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



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

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


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







var arr=new Array();
// Get the data
d3.json("data/data3.php", function(error, data) { 

color.domain(d3.keys(data[0]).filter(function(key) {  if(key !== "date"&&key !== "close") return key; }));


    data.forEach(function(d,i) {




    d.date = parseDate(d.date);

        d.close = +d.close;
    d.mean=+d.mean;
    d.ucl=+d.ucl;
    d.lcl=+d.lcl;   

    arr[i]=d.close;


    len=i+1;


    });


var cities = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {date: d.date, limit: +d[name]};
      })
    };
  });






 var min=0;
var max=200;
// Scale the range of the data

    x.domain(d3.extent(data, function(d) { return d.date; }));

  //  y.domain([min-10, max+10]);
    //y.domain([0, d3.max(data, function(d) { return d.ucl; })]);

y.domain([
    d3.min(cities, function(c) { return d3.min(c.values, function(v) { return v.limit; }); }),
    d3.max(cities, function(c) { return d3.max(c.values, function(v) { return v.limit; }); })
  ]);

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


    //y.domain([lsl-5, d3.max(data, function(d) { return d.close; })]);


  var city= focus.selectAll(".city")
      .data(cities)
      .enter().append("g")
      .attr("class", "city");

    city.append("path")
      .attr("class", "line")
      .attr("d", function(d) { return line(d.values); })
      .style("stroke", function(d) { return color(d.name); });







   focus.append("path")     // Add the valueline path.
    .datum(data)
        .attr("class","valueline")
    .attr("d", valueline);

    focus.selectAll(".dot").data(data).enter().append("a").attr("class", "dot")
        .attr("xlink:href",function(d,i){if(d.close>=d.ucl||d.close<=d.lcl)return "http://en.wikipedia.org";})
    .append("circle")
        .attr("r", 2)
    .style("fill", function(d,i) {            // <== Add these
        if(d.close==0) {return "none"}              
        if(d.close>=d.ucl||d.close<=d.lcl) {return "red"}

            else    { return "steelblue" }          // <== Add these
        ;})  
        .attr("cx", function(d) { return x(d.date); })
        .attr("cy", function(d) { return y(d.close); })
    .on("mouseover", function(d,i) {

            div.transition()        
                .duration(200)      
                .style("opacity", .9);      
                div.html(function(){
    if(d.close==0)
    {return}
    if(d.close>=d.ucl)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " > UPPER LIMIT"}
    else if(d.close<=lcl)
    {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b><br/>"  + " < LOWER LIMIT"}

    else {return formatTime(d.date) + "<br/><b>"  + d.close+ "</b>"}
;})
                .style("left", (d3.event.pageX) + "px")     
                .style("top", (d3.event.pageY - 28) + "px");    
            })                  
        .on("mouseout", function(d) {       
            div.transition()        
                .duration(500)      
                .style("opacity", 0);
       }).style("pointer-events","visible");




    /*
city.append("text")
      .datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
      .attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.limit) + ")"; })
      .attr("x", 3)
      .attr("dy", ".35em")
      .text(function(d) { return d.name; });

*/
            // Add the X Axis

    focus.append("g").attr("class", "x axis").attr("transform", "translate(0," + height + ")").call(xAxis)
    .selectAll("text")  
            .style("text-anchor", "end")
            .attr("dx", "-.8em")
            .attr("dy", ".15em")
            .attr("transform", function(d) {
                return "rotate(-65)" 
                });


    focus.append("text")             // text label for the x axis
        .attr("x", width/2 )
        .attr("y",  height+margin.bottom)
        .style("text-anchor", "middle")
        .text("Date");  

// Add the Y Axis

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

    focus.append("text").attr("transform","rotate(-90)").attr("y", 0-margin.left+10 )
        .attr("x",0-( height/2) )
        .style("text-anchor", "middle")
    .style("text-decoration", "underline")  
        .text("issue"); 

    //title to graph
focus.append("text")
        .attr("x", (width / 2))             
        .attr("y", 0 - (margin.top / 2))
        .attr("text-anchor", "middle")  
        .style("font-size", "16px") 
        .style("text-decoration", "underline")  
        .text("Issue vs Date Graph");


context.append("path")      // Add the valueline path.
        .attr("d", valueline2(data));

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);



});


function brushed() {

  x.domain(brush.empty() ? x2.domain() : brush.extent());


  focus.selectAll(".valueline").attr("d",valueline);
  focus.selectAll(".dot").select("circle").attr("cx", function(d) { return x(d.date); });
  focus.selectAll(".city").attr("d",line);
  focus.select(".x.axis").call(xAxis);
}

function type(d) {
  d.date = parseDate(d.date);
  d.close = +d.close;
  d.ucl=+d.ucl;
  d.lcl=+d.lcl;
  d.mean=+d.mean;
  return d;
}




</script>

</body>
<html>