2013-05-05 59 views
3

我已經實現了一個d3線圖,它從CSV文件中讀取數據,然後繪製對mouseover事件作出反應的多行。它工作正常使用下面的代碼(抱歉,這是這麼久,稍有凌亂,但我覺得最好還是顯示完整的代碼)的平移和縮放:帶有限變焦的d3圖形

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

    var margin = {top: 50, right: 120, bottom: 50, left: 70}, 
    width = 1200 - margin.left - margin.right, 
    height = 800 - margin.top - margin.bottom; 

    var parseDate = d3.time.format("%m%d").parse; 

    var color = d3.scale.category20(); 

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

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

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

    var x = d3.time.scale() 
     .range([0, width]) 
     .domain([ 
     d3.min(data, function(d) { return d.date; }), 
     d3.max(data, function(d) { return d.date; }) 
    ]); 

    var y = d3.scale.linear() 
     .range([height, 0]) 
     .domain([ 
     0, 
     d3.max(sources, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); }) 
    ]); 

    var xAxis = d3.svg.axis() 
     .scale(x) 
     .orient("bottom") 
     .ticks(12) 
     .tickFormat(d3.time.format("%b %d")); 

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

    var line = d3.svg.line() 
     .defined(function(d) { return d.temperature >= 0; }) 
     .x(function(d) { return x(d.date); }) 
     .y(function(d) { return y(d.temperature); }); 

    var zoom = d3.behavior.zoom() 
    .x(x) 
    .y(y) 
    .scaleExtent([1, 8]) 
    .on("zoom", zoomed); 

    var svg = d3.select("body").append("svg") 
    .attr("width", "100%") 
    .attr("height", "100%") 
    .attr("viewBox", "0 0 1200 800") 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
    .call(zoom); 

    var rect = svg.append("svg:rect") 
    .attr("width", width) 
    .attr("height", height) 
    .attr("class", "plot"); 

    var make_x_axis = function() { 
     return d3.svg.axis() 
      .scale(x) 
      .orient("bottom") 
      .ticks(12) 
      .tickFormat(d3.time.format("%b %d")); 
    }; 

    var make_y_axis = function() { 
     return d3.svg.axis() 
      .scale(y) 
      .orient("left") 
      .ticks(5); 
    }; 

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

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

    svg.append("g") 
     .attr("class", "x grid") 
     .attr("transform", "translate(0," + height + ")") 
     .call(make_x_axis() 
     .tickSize(-height, 0, 0) 
     .tickFormat("")); 

    svg.append("g") 
     .attr("class", "y grid") 
     .call(make_y_axis() 
     .tickSize(-width, 0, 0) 
     .tickFormat("")); 

    var source = svg.selectAll(".source") 
    .data(sources) 
    .enter().append("g") 
    .attr("class", "source"); 

    var clip = svg.append("clipPath") 
    .attr("id", "clip") 
    .append("rect") 
    .attr("x", 0) 
    .attr("y", 0) 
    .attr("width", width) 
    .attr("height", height) 
    .append("text"); 

    source.append("path") 
     .data(sources) 
     .attr("class", "line") 
     .attr("clip-path", "url(#clip)") 
     .attr("d", function(d) { return line(d.values); }) 
     .style("stroke", function(d) {return color(d.name);}) 
     .style("opacity", 0.8) 
     .on("mouseover", function(d){ 
      d3.select(this) 
       .style("stroke",function(d) {return color(d.name);}) 
       .style("opacity", 1.0) 
       .style("stroke-width", 2.5); 
       this.parentNode.parentNode.appendChild(this.parentNode); 
      d3.select('#text-' + d.name) 
       .style("fill",function(d) {return color(d.name);}) 
       .style("font-weight", 700); 
     }) 
     .on("mouseout", function(d) { 
      d3.select(this) 
       .transition() 
       .duration(250) 
       .style("stroke", function(d) {return color(d.name);}) 
       .style("stroke-width", 1.5) 
       .style("opacity", 0.8); 
      d3.select('#text-' + d.name) 
       .transition() 
       .duration(250) 
       .style("fill", function(d) {return color(d.name);}) 
       .style("font-weight", 400); 
     }) 
     .attr("id", function(d, i) { return "path-" + d.name; }); 

    source.append("text") 
     .datum(function(d) { return {name: d.name}; }) 
     .attr("x", function(d, i) { return width+10; }) 
     .attr("y", function(d, i) { return (i*(height/16)); }) 
     .style("fill", function(d) {return color(d.name);}) 
     .on("mouseover", function(d){ 
      d3.select('#path-' + d.name) 
       .style("stroke",function(d) {return color(d.name);}) 
       .style("opacity", 1.0) 
       .style("stroke-width", 2.5); 
       this.parentNode.parentNode.appendChild(this.parentNode); 
      d3.select(this) 
       .style("fill",function(d) {return color(d.name);}) 
       .style("font-weight", 700); 
     }) 
     .on("mouseout", function(d) { 
      d3.select('#path-' + d.name) 
       .transition() 
       .duration(250) 
       .style("stroke", function(d) {return color(d.name);}) 
       .style("stroke-width", 1.5) 
       .style("opacity", 0.8); 
      d3.select(this) 
       .transition() 
       .duration(250) 
       .style("fill", function(d) {return color(d.name);}) 
       .style("font-weight", 400); 
     }) 
     .text(function(d) { return d.name; }) 
     .attr("font-family","sans-serif") 
     .attr("font-size","14px") 
     .attr("id", function(d, i) { return "text-" + d.name; } 
     ); 

    var minT = new Date('01/01/1900'), maxT = new Date('01/01/2002'), w = $(window).width(); 

function zoomed() { 
     d3.event.translate; 
     d3.event.scale; 

    svg.select(".x.axis") 
     .call(xAxis); 
    svg.select(".y.axis").call(yAxis); 
    svg.select(".x.grid") 
     .call(make_x_axis() 
     .tickSize(-height, 0, 0) 
     .tickFormat("")); 
    svg.select(".y.grid") 
     .call(make_y_axis() 
     .tickSize(-width, 0, 0) 
     .tickFormat("")); 
    source.select(".line") 
     .attr("d", function(d) { return line(d.values); }) 
     .style("stroke", function(d) {return color(d.name);}); 
    } 

    }); 

我的問題是,我想限制平移和縮放,以便圖形無法放大或平移離屏。我可以通過設置scaleExtent上的變焦(在上面的例子中實現)和改變縮放函數來做到這一點:

function zoomed() { 

    var t = zoom.translate(), 

    tx = t[0]; 
    ty = t[1]; 

    tx = Math.min(tx, 0); 
    zoom.translate([tx, ty]); 

    d3.event.translate; 
    d3.event.scale; 

    svg.select(".x.axis") 
     .call(xAxis); 
    svg.select(".y.axis").call(yAxis); 
    svg.select(".x.grid") 
     .call(make_x_axis() 
     .tickSize(-height, 0, 0) 
     .tickFormat("")); 
    svg.select(".y.grid") 
     .call(make_y_axis() 
     .tickSize(-width, 0, 0) 
     .tickFormat("")); 
    source.select(".line") 
     .attr("d", function(d) { return line(d.values); }) 
     .style("stroke", function(d) {return color(d.name);}); 
} 

這限制了x軸的最小爲零。然而,儘管我努力嘗試,但我無法限制x軸的最大值,這意味着圖形仍然可能偏移太遠。

任何幫助?我希望這是有道理的!

尼克

回答

3

你可以簡單的手動檢查的價值和重置它,如果它是太高:

if(tx > threshold) { tx = threshold; } 

此外,報表

d3.event.translate; 
d3.event.scale; 

在你的代碼沒有任何效果。

4

感謝您的幫助,我做到了,在結束下面的代碼:

var t = zoom.translate(), 
s = zoom.scale(); 

tx = Math.min(0, Math.max(width * (1 - s), t[0])); 
ty = Math.min(0, Math.max(height * (1 - s), t[1])); 

zoom.translate([tx, ty]); 

的困難是在邊界在不同的縮放級別,此解決現在的圖表。 d3.event.translate和d3.event.scale語句也是不必要的,應該被刪除。