首页 > 解决方案 > D3.js:多折线图中的线条在更新时未正确转换(位置和颜色)

问题描述

我有多个多线图表,用户可以使用页面顶部的单选按钮在它们之间移动。JSFiddle:https ://jsfiddle.net/etonblue/wh07bk1u/6/ 。我在换行时遇到两个问题:

  1. 更新时不会删除某些行。例如,如果您单击“Annual Enrollment Change %”单选按钮,您可以在底部附近看到两条绿线(没有点的那些),它们是“Current Ratio”图表中的“剩余”。更新功能正确地使用新数据来绘制新的绿线(带点的线),而不是转换/删除旧的绿线。在其他情况下,您也可以通过不同的线条看到这一点(例如,点击偿债覆盖率,然后点击 Aggregated 3-Year Total Margin - 绿色线和不带点的粉色线)。我仍在尝试确定模式,但我的假设是这是由于我更新线条的方式。编辑:添加更多代码

我的初始图表:

var initialChart = function(m){

    var selectMetric = nestData.filter(d => d.key == m);

    var metricGroup = svg.selectAll(".metricGroup")
        .data(selectMetric, d => d ? d.key : this.key)
        .enter()
        .append("g")
        .attr("class", "metricGroup")
        .each(function(d){
            x.domain([(d.value.ymin - .5), (d.value.ymax + .5)])
            y.domain([(ydom[(m-1)][0]), (ydom[(m-1)][1])])
        })

    var lineGroup = metricGroup.selectAll(".lineGroup")
        .attr("class", "lineGroup")
        .data(d => d.value.school)
        .enter()

    lineGroup.append("path")
        .attr("d", d => line(d.values))
        .attr("class", "line " + "slash" + m)
        .attr('id', function (d) {
            return d.key.replace(/\s+/g, '') + m;
        })
        .attr("transform", `translate(0, 0)`)
        .attr("fill", "none")
        .attr("stroke", d => color(d.key))
        .attr("stroke-linecap", "round")
        .attr("stroke-linejoin", "round")
        .attr("stroke-width", 2)

    lineGroup.selectAll("circle")
        .data(d => d.values)
        .enter()
        .append("circle")
        .attr("class", "dot " + "dab" + m)
        .attr('id', function (d) {
            return d.school.replace(/\s+/g, '') + m;
        })
        .attr("cx", d => x(d.year))
        .attr("cy", 0)
        .style('fill', d => color(d.school))
        .transition()
        .delay(function(d,i){return(i*2)})
        .duration(500)
        .attr("r", 4)
        .attr("cx", d => x(d.year))
        .attr("cy", d => d.mval < y.domain()[0] ? y(y.domain()[0]) : d.mval > y.domain()[1] ? y(y.domain()[1]) : y(d.mval))

    var xAxis = svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x).ticks(8).tickFormat(d3.format("d")))
        .call(g => {
                g.selectAll("text")
                    .style("text-anchor", "middle")
                    .attr('fill', '#A9A9A9')
                g.selectAll("line")
                    .attr('stroke', '#A9A9A9')
                g.select(".domain")
                    .attr('stroke', '#A9A9A9')
            })

    var yAxis = svg.append("g")
        .attr("class", "y axis")
        .attr("transform", `translate(0, 0)`)
        .call(d3.axisLeft(y).ticks(28, "s").tickSize(-width).tickFormat(d3.format(",.2f")))
        .call(g => {
            g.selectAll("text")
                .attr('fill', '#A9A9A9')
            g.selectAll("line")
                .attr('stroke', '#A9A9A9')
                .attr('stroke-width', 0.7)
                .attr('opacity', 0.3)
            g.select(".domain").remove()
        })
        .append('text')
            .attr("transform", "rotate(-90)")
            .attr("y", 0 - 60)
            .attr("x", 0 - (height / 2))
            .attr("dy", "1em")
            .attr("fill", "#A9A9A9")
            .style("text-anchor", "middle")
            .text(yname[m-1])
            .attr("class", "y axis label")
}

更新功能:

var updateChart = function(m){
var selectMetric = nestData.filter(d => d.key == m);

    var metricGroup = svg.selectAll(".metricGroup")
        .data(selectMetric, d => d ? d.key : this.key)
        .enter()
        .append("g")
        .attr("class", "metricGroup")
        .each(function(d){
            x.domain([(d.value.ymin - .5), (d.value.ymax + .5)])
            y.domain([-2,20])
        })

    var lineGroup = metricGroup.selectAll(".lineGroup")
        .attr("class", "lineGroup")
        .data(d => d.value.school)
        .enter()

    lineGroup.append("path")
        .attr("d", d => line(d.values))
        .attr("class", "line")
        .attr('id', function (d) {return d.key.replace(/\s+/g, '');})
        .attr("transform", `translate(0, 0)`)
        .attr("fill", "none")
        .attr("stroke", d => color(d.key))
        .attr("stroke-width", 2)
  1. 我遇到的另一个问题似乎与我的图例/onClick/onMouseout 功能有关。如果单击每个度量单选按钮,所有颜色(线和点)都会正确绘制。但是,如果您单击其中一个图例标签、鼠标移出,然后通过单击不同的单选按钮移动到不同的图表,则许多“线”以不正确的颜色绘制,并且它们保持不正确的颜色,直到您移动您的鼠标移出图例。我再次试图追踪为什么会发生这种情况(以及为什么它会影响某些行而不影响其他行),但到目前为止还没有运气。

设置颜色:

    var schoolnames = allData.map(d => d.school).filter((value, index, self) => self.indexOf(value) === index)

    var color = d3.scaleOrdinal()
        .domain(schoolnames)
        .range(["#393b79","#5254a3","#6b6ecf","#9c9ede","#637939","#8ca252","#b5cf6b","#cedb9c","#8c6d31","#bd9e39","#e7ba52","#e7cb94","#843c39","#ad494a","#d6616b","#6baed6","#9ecae1","#c6dbef","#e6550d","#fd8d3c","#e7969c","#7b4173","#a55194","#ce6dbd","#de9ed6","#3182bd","#fdae6b","#fdd0a2","#31a354","#74c476","#a1d99b","#c7e9c0","#756bb1","#9e9ac8","#bcbddc","#dadaeb"])

“onClick”函数(没有工具提示代码)。请注意,工具提示在浏览器中工作正常,但在 JSFiddle 中没有正确定位。

function onClick(sel) {

    svg.selectAll(".line")
        .transition().duration(200)
        .style("stroke", "lightgrey")
        .style("opacity", "0.2")
        
    svg.selectAll(".dot")
        .transition().duration(200)
        .style("fill", "lightgrey")
        .style("opacity", "0.2")

    svg.selectAll("#" + sel.replace(/\s+/g, '')).raise()
        .transition()
        .select('.line')
        .style("stroke", function(d) {return color(sel)})
        .attr("stroke-width", 3)
        .style("opacity", "1")
// do separate line and dot selections do anything? //
        .select('.dot')
        .style("fill", function(d) {return color(sel)})
        .style("opacity", "1")

    d3.select('#key').selectAll('li')
        .select(d => d===sel?this:null)
        .transition().duration(200)
        .style('background', '#ededed')
}

onMouseout 函数:

function onMouseout (sel) {

    svg.selectAll(".line")
        .transition()
        .duration(200).delay(50)
        .style("stroke", function(d) {
            return color(d.key)
        })
        .attr("stroke-width", 2)
        .style("opacity", "1")
 
    svg.selectAll(".dot")
        .transition().duration(200).delay(50)
        .style("fill", function(d) {
            return color(d.school)
        })
        .style("opacity", "1")

    d3.select('#key').selectAll('li')
        .select(d => d===sel?this:null)
        .transition().duration(500)
        .style('background', '#ffffff')
}

任何建议,将不胜感激。

标签: javascriptd3.js

解决方案


推荐阅读