为什么在交互式多系列折线图中使用 brushed() 时只有一条线被扩展



我正在使用d3制作多系列折线图.js并且我正在尝试实现 http://bl.ocks.org/mbostock/1667367 中看到的焦点和上下文缩放。我已经将示例中的面积图转换为具有单个系列的折线图,但我无法弄清楚为什么在使用刷子扩展 x 域时我的所有线都没有被扩展。只有X域和一行正在根据新的X域范围进行扩展。

这是我正在使用的代码...

var margin = {
        top: 20,
        right: 200,
        bottom: 100,
        left: 100
    },
    margin2 = {
        top: 430,
        right: 10,
        bottom: 20,
        left: 100
    },
    height = 500 - margin.top - margin.bottom,
    height2 = 500 - margin2.top - margin2.bottom,
    legendPanel = {
        width: 80
    },
    width = 960 - margin.left - margin.right - legendPanel.width;
var data = [{
    "symbol": "Banker",
    "date": "20000112",
    "earnedpts": "30",
    "redeemedpts": "15"
}, {
    "symbol": "Banker",
    "date": "20000810",
    "earnedpts": "10",
    "redeemedpts": "8"
}, {
    "symbol": "Banker",
    "date": "20010618",
    "earnedpts": "50",
    "redeemedpts": "20"
}, {
    "symbol": "Banker",
    "date": "20011220",
    "earnedpts": "40",
    "redeemedpts": "20"
}, {
    "symbol": "Banker",
    "date": "20020220",
    "earnedpts": "30",
    "redeemedpts": "20"
}, {
    "symbol": "Banker",
    "date": "20021130",
    "earnedpts": "10",
    "redeemedpts": "5"
}, {
    "symbol": "Health",
    "date": "20000112",
    "earnedpts": "20",
    "redeemedpts": "15"
}, {
    "symbol": "Health",
    "date": "20000810",
    "earnedpts": "40",
    "redeemedpts": "28"
}, {
    "symbol": "Health",
    "date": "20010618",
    "earnedpts": "30",
    "redeemedpts": "20"
}, {
    "symbol": "Health",
    "date": "20011220",
    "earnedpts": "60",
    "redeemedpts": "35"
}, {
    "symbol": "Health",
    "date": "20020220",
    "earnedpts": "30",
    "redeemedpts": "25"
}, {
    "symbol": "Health",
    "date": "20021130",
    "earnedpts": "20",
    "redeemedpts": "15"
}, {
    "symbol": "Govt",
    "date": "20000112",
    "earnedpts": "80",
    "redeemedpts": "65"
}, {
    "symbol": "Govt",
    "date": "20000810",
    "earnedpts": "60",
    "redeemedpts": "48"
}, {
    "symbol": "Govt",
    "date": "20010618",
    "earnedpts": "60",
    "redeemedpts": "40"
}, {
    "symbol": "Govt",
    "date": "20011220",
    "earnedpts": "30",
    "redeemedpts": "15"
}, {
    "symbol": "Govt",
    "date": "20020220",
    "earnedpts": "40",
    "redeemedpts": "25"
}, {
    "symbol": "Govt",
    "date": "20021130",
    "earnedpts": "30",
    "redeemedpts": "5"
}, {
    "symbol": "BPO",
    "date": "20000112",
    "earnedpts": "70",
    "redeemedpts": "45"
}, {
    "symbol": "BPO",
    "date": "20000810",
    "earnedpts": "60",
    "redeemedpts": "30"
}, {
    "symbol": "BPO",
    "date": "20010618",
    "earnedpts": "40",
    "redeemedpts": "25"
}, {
    "symbol": "BPO",
    "date": "20011220",
    "earnedpts": "70",
    "redeemedpts": "50"
}, {
    "symbol": "BPO",
    "date": "20020220",
    "earnedpts": "40",
    "redeemedpts": "25"
}, {
    "symbol": "BPO",
    "date": "20021130",
    "earnedpts": "50",
    "redeemedpts": "30"
}];
var parsedate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale().range([0, width]);
x2 = d3.time.scale()
    .range([0, width]);
var y = d3.scale.linear().range([height, 0]);
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x)
    .orient("bottom");
var xAxis2 = d3.svg.axis()
    .scale(x2)
    .orient("bottom");
var yAxis = d3.svg.axis().scale(y)
    .orient("left");
var color = d3.scale.ordinal()
    .range(["#04b0ff", "#04ffa8", "#ff5404", "#8a89a6", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var brush = d3.svg.brush()
    .x(x2)
    .on("brush", brushed);
var extent = brush.extent();
var rangeExtent = [x2(extent[0]), x2(extent[1])];
var rangeWidth = rangeExtent[1] - rangeExtent[0];
var priceline1 = d3.svg.line()
    .x(function(d) {
        return x(d.date);
    })
    .y(function(d) {
        return y(d.earnedpts);
    })
    .interpolate("linear");
var priceline2 = d3.svg.line()
    .x(function(d) {
        return x(d.date);
    })
    .y(function(d) {
        return y(d.redeemedpts);
    })
    .interpolate("linear");
var svg = d3.select("body")
    .append("svg")
    .attr("width", width + margin.left + margin.right + legendPanel.width)
    .attr("height", height + margin.top + margin.bottom);
var focus = svg.append("g")
    .attr("class", "focus")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
    .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")")
    .attr("class", "context");
svg.append("defs")
    .append("clipPath")
    .attr("id", "clip")
    .append("rect")
    .attr("width", width)
    .attr("height", height);
data.forEach(function(d) {
    d.date = parsedate(d.date);
    d.earnedpts = +d.earnedpts;
    d.redeemedpts = +d.redeemedpts;
});
x.domain(d3.extent(data, function(d) {
    return d.date;
}));
x2.domain(x.domain());
y.domain([0, d3.max(data, function(d) {
    return Math.max(d.earnedpts, d.redeemedpts);
})]);
y2.domain(y.domain());
var dataNest = d3.nest()
    .key(function(d) {
        return d.symbol;
    })
    .entries(data);
dataNest.forEach(function(d) {
    focus.append("path")
        .attr("class", "line")
        .style("stroke", function() {
            return d.color = color(d.key);
        })
        .attr("d", priceline1(d.values))
});
dataNest.forEach(function(d) {
    focus.append("path")
        .attr("class", "line")
        .style("stroke", function() {
            return d.color = color(d.key);
        })
        .style("stroke-dasharray", ("3, 3"))
        .attr("d", priceline2(d.values))
});
context.append("g")
    .attr("class", "x axis1")
    .attr("transform", "translate(0," + height2 + ")")
    .call(xAxis2);
var contextArea = d3.svg.area()
    .interpolate("monotone")
    .x(function(d) {
        return x2(d.date);
    })
    .y0(height2)
    .y1(0);
context.append("path")
    .attr("class", "area")
    .attr("d", contextArea(dataNest[0].values))
    .attr("fill", "#F1F1F2");
context.append("g")
    .attr("class", "x brush")
    .call(brush)
    .selectAll("rect")
    .attr("height", height2)
    .attr("fill", "#E6E7E8");
focus.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis)
    .append("text")
    .attr("x", -30)
    .attr("y", 6)
    .attr("dy", ".71em")
    .style("text-anchor", "end")
    .text("Days");
focus.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("x", 0)
    .attr("y", -40)
    .attr("dy", ".71em")
    .style("text-anchor", "end")
    .text("Average points Earned & Redeemed");

dataNest.forEach(function(d, i) {
    focus.append("text")
        .attr("transform", "translate(" + width + "," + y(data[dataNest[i].values.length + i * 6 - 1].earnedpts) + ")")
        .attr("dy", ".35em")
        .attr("text-anchor", "start")
        .style("fill", function() {
            return d.color = color(d.key);
        })
        .text(d.key);
});
focus.append("text")
    .attr("transform", "translate(" + (width - 20) + ",5)")
    .attr("dy", ".35em")
    .attr("text-anchor", "start")
    .style("fill", "black")
    .text("Points Earned");
focus.append("text")
    .attr("transform", "translate(" + (width - 20) + "," + (y(data[0].redeemedpts) - 245) + ")")
    .attr("dy", ".35em")
    .attr("text-anchor", "start")
    .style("fill", "black")
    .text("Points Redeemed");
function brushed() {
    x.domain(brush.empty() ? x2.domain() : brush.extent());
    focus.select(".x.axis").transition().call(xAxis);
    focus.select(".y.axis").transition().call(yAxis);
    dataNest.forEach(function(d) {
        focus.selectAll("path")
            .style("stroke", function() {
                return d.color = color(d.key);
            })
            .transition()
            .attr("d", priceline1(d.values))
    });
}

我认为这里有一些问题。

首先,使用两种不同的线条方法创建两种类型的直线(虚线和实线)。那很好。但是,在最后的更新方法中,您选择了所有这些方法并仅使用一种绘制方法 ( priceline )。我建议以下修改:

  1. 向每行添加一个类标识符,如 line1line2,如下所示:

    dataNest.forEach(function (d) {
     focus.append("path")
       .attr("class", "line line1-" + d.key)
       .style("stroke", function () {
       return color(d.key);
     })
    .attr("d", priceline1(d.values));
    });
    

    dataNest.forEach(function (d) {
     focus.append("path")
       .attr("class", "line line2-" + d.key)
       .style("stroke", function () {
      return color(d.key);
    })
    .style("stroke-dasharray", ("3, 3"))
    .attr("d", priceline2(d.values));
    });
    
  2. 然后,在画笔事件上,选择适当的并更新线条。(抱歉,我不知道您要更新哪一个,所以我将它们都包括在内)

    function brushed() {
        x.domain(brush.empty() ? x2.domain() : brush.extent());
        focus.select(".x.axis").transition().call(xAxis);
        focus.select(".y.axis").transition().call(yAxis);
        dataNest.forEach(function (d) {
            focus.selectAll(".line1-" + d.key)
                .transition().duration(200)
                .attr("d", priceline1(d.values));
            focus.selectAll(".line2-" + d.key)
                .transition().duration(200)
                .attr("d", priceline2(d.values));
        });
    }
    

小提琴在这里。

关于缩放格式,可以使用tickFormat方法,如下所示:

// First define a formatting method such as
var axisFormat = d3.time.format("%b")
// Then apply your tickFormat to your scale
var xAxis = d3.svg.axis()
                  .scale(x)
                  .orient("bottom")
                  .tickFormat(function(d) {
                      v=axisFormat(d); 
                      return v.substr(0,1) // you can adjust this.
                   });

希望这有帮助

相关内容

最新更新