2017-01-11 8 views
1

初心者の質問に対するお詫び私はこの例をhttps://bl.ocks.org/mbostock/3884955のオンラインインフルエンサーのデータ(基本的には多くの行を描く)で再現しようとしていますが、データの一部を分離するためにスクロールズームを使用しています。十分にシンプルな音が、私はそれが機能するように見えることはできません!D3マルチシリーズライングラフ(ズーム付き)

< svg width = "960" 
height = "500" > < /svg> 
<script src="//d3js.org/d3.v4.min.js "></script> 
<script> 

var svg = d3.select("svg"), 
    margin = {top: 20, right: 80, bottom: 30, left: 100}, 
    width = svg.attr("width") - margin.left - margin.right, 
    height = svg.attr("height") - margin.top - margin.bottom, 
    g = svg.append("g").attr("transform ", "translate(" + margin.left + 
      ", " + margin.top + ")"); 

var zoom = d3.zoom() 
    .scaleExtent([1, 32]) 
    .translateExtent([[0, 0], [width, height]]) 
    .extent([[0, 0], [width, height]]) 
    .on("zoom", zoomed); 

var xAxis = d3.axisBottom(x), 
    yAxis = d3.axisLeft(y); 

var parseTime = d3.timeParse(" % d/% m/% Y "); 

var x = d3.scaleTime().range([0, width]), 
    y = d3.scaleLinear().range([height, 0]), 
    z = d3.scaleOrdinal(d3.schemeCategory10); 

var line = d3.line() 
    .curve(d3.curveBasis) 
    .x(function(d) { return x(d.date); }) 
    .y(function(d) { return y(d.engagement); }); 

d3.csv("stack2.csv", type, function(error, data) { 
    if (error) throw error; 

    var influencers = data.columns.slice(1).map(function(id) { 
    return { 
     id: id, 
     values: data.map(function(d) { 
     return {date: d.date, engagement: d[id]}; 
     }) 
    }; 
    }); 


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

    y.domain([d3.min(influencers, function(c) { 
     return d3.min(c.values, function(d) { 
      return d.engagement; }); }), 
d3.max(influencers, function(c) { 
     return d3.max(c.values, function(d) { 
      return d.engagement; }); }) 
    ]); 

    z.domain(influencers.map(function(c) { return c.id; })); 

    g.append("g") 
     .attr("class", "axis axis--x") 
     .attr("transform", "translate(0, " + height + ")") 
     .call(d3.axisBottom(x)); 

    g.append("g") 
     .attr("class", "axis axis--y") 
     .call(d3.axisLeft(y)) 
    .append("text") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 5) 
     .attr("dy", "0.71em") 
     .attr("fill", "#000") 
     .text("Engagement"); 

var influ = g.selectAll(".influ") 
    .data(influencers) 
    .enter().append("g") 
    .attr("class", "influ"); 

influ.append("path") 
    .attr("class", "line") 
    .attr("d", function(d) { 
    return line(d.values); 
    }) 
    .style("stroke", "lightgrey") 
    .on("mouseover", function(d, i) { 
    d3.select(this).transition() 
     .style("stroke", function(d) { 
     return z(d.id); 
     }) 
     .style("stroke-width", 3) 
    console.log(d.id); 
    }) 
    .on("mouseout", function(d) { 
    d3.select(this).transition() 
     .style("stroke", "lightgrey") 
     .style("stroke-width", 1) 
    }) 


influ.append("text") 
    .datum(function(d) { 
    return { 
     id: d.id, 
     value: d.values[d.values.length - 1] 
    }; 
    }) 
    .attr("transform", function(d) { 
    return "translate(" + x(d.value.date) + "," + y(d.value.engagement) + ")"; 
    }) 
    .attr("x", 3) 
    .attr("dy", ".35em") 
    .style("opacity", 0.7) 
    .style("font", "10px sans-serif") 
    .text(function(d) { 
    return d.id; 
    }); 

svg.call(zoom) 

}); 

function type(d, _, columns) { 
    d.date = parseTime(d.date); 
    for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +d[c]; 
    return d; 
} 

function zoomed() { 
    var t = d3.event.transform, 
    xt = t.rescaleX(x); 
    g.selectAll("path.line").attr("d", function(d) { 
    return xt(d.date); 
    }); 
    g.select(".axis--x").call(xAxis.scale(xt)); 
} 

< /script> 

私は、問題はこの部分に隔離されていると思う:

function zoomed() { 
    var t = d3.event.transform, 
    xt = t.rescaleX(x); 
    g.selectAll("path.line").attr("d", function(d) { 
    return xt(d.date); 
    }); 
    g.select(".axis--x").call(xAxis.scale(xt)); 
} 

軸ズームは結構ですが、私は私が正しく折れ線グラフのデータを呼んでいるとは思いません。私はg.selectAllが間違いなくスクロールで消えるように、ラインを選択すると思います...だから私は.attr("d", function(d) {return xt(d.date);が間違っていると仮定しています。誰もが任意のヒントを持っていますか?

+0

私はそれを働かせています...しかし、非常に純粋ではありません。 – HGalan

答えて

1

インタラクティブな折れ線グラフD3プロットで、これらの線に沿って何かを使用して、数日前に書きました。私は広範囲にコメントしたので、それはかなり説明する必要があります。これは本当にうまく動作し、バグがなくなっています。

function zoomed() { 
    lastEventTransform = d3.event.transform; 

    // Rescale axes using current zoom transform 
    gX.call(xAxis.scale(lastEventTransform.rescaleX(x))); 
    gY.call(yAxis.scale(lastEventTransform.rescaleY(y))); 

    // Create new scales that incorporate current zoom transform on original scale 
    var xt = lastEventTransform.rescaleX(x), 
     yt = lastEventTransform.rescaleY(y); 

    // Apply new scale to create new definition of d3.line method for path drawing of line plots 
    var line = d3.line() 
     .x(function(d) { return xt(d.x); }) 
     .y(function(d) { return yt(d.y); }); 

    // Update all line-plot elements with new line method that incorporates transform 
    innerSvg.selectAll(".line") 
     .attr("d", function(d) { return line(d.values); }); 

    // Update any scatter points if you are also plotting them 
    innerSvg.selectAll(".dot") 
     .attr("cx", function(d) {return xt(d.x); }) 
     .attr("cy", function(d) {return yt(d.y); }); 
} 

注:gXgYはもともと、プロットのセットアップ時にそれらに呼ばれるの軸を持っていただけで、D3 g族元素です。

+0

ありがとうございます。もう少し簡単な質問:innerSvgとは何を指していますか? – HGalan

+0

ああ、innerSvgは、プロット領域(2つの軸をその辺に持つ矩形)のみのサイズのネストSVGブロックです。私は内側のSVGにすべての私の線/円をプロットします。これは、 'g'要素がSVG要素をクリップしないためです。したがって、プロットを拡大すると、線と円は軸の外側(目盛とラベルがある領域)にプロットされます。一部の人々は、g要素に対してこれを防ぐためにCSSクリップ属性を使用しますが、ズームするためにブラシを使用している場合はうまく機能しません。 – HamsterHuey

+0

@HGalan - この回答はあなたの問題に役立ちましたか? – HamsterHuey

0

このズーム機能は、ドメインを変更して新しいドメインの行を再描画するようトリックします。その最高の私は今管理することができます...しかし、ほとんどエレガント!

function zoomed() { 
    var t = d3.event.transform; 
    // var t = d3.event.scaleBy; 
    var xt = t.rescaleY(y); 
    domain = yAxis.scale().domain(); 
    g.select(".axis--y").call(yAxis.scale(xt)); 

    g.selectAll("path.line").attr("d", function(d) { 
    if (d3.max(d.values.map(function(dd) { return dd.engagement })) > domain[1]) { 
     return null 
    } 
    else { 
     return line(d.values) 
    } 
    }); 



    if (domain[1] > 50000000) { 
    max = 50000000 
    } else if (domain[1] < 500) { 
    max = 500 
    } else { 
    max = domain[1] 
    } 

    y.domain([0, max]); 
} 

これは問題ありませんが、軸が軸から外れてしまうことがあります。誰かが何かを持っているなら私に知らせてください!