2013-04-04 55 views
3

我有一個d3焦點/上下文圖表,我希望能夠在刷新上下文之後在焦點部分上平移,並且我希望上下文的拉絲部分區域與焦點區域的平移同步移動。但是,當我在上下文圖表中選擇區域後單擊焦點部分時,焦點比例會發生變化,並且點不再顯示在正確的座標上。下面的代碼可以在jsfiddle還有:D3焦點/上下文圖表:刷牙和平移的同步

<html> 
    <head> 
     <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 
     <title> - jsFiddle demo</title> 
     <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script> 
     <link rel="stylesheet" type="text/css" href="/css/result-light.css"> 
     <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
     <style type="text/css"> 
     circle { 
     -webkit-transition: fill-opacity 250ms linear; 
     } 
     .selecting circle { 
     fill-opacity: .5; 
     } 
     .selecting circle.selected { 
     stroke: #f00; 
     } 
     .brush .extent { 
     stroke: #B8C6D0; 
     fill-opacity: .125; 
     shape-rendering: crispEdges; 
     } 
     #context .axis path.domain { 
     stroke: lightsteelblue; 
     stroke-width: 5px; 
     } 
     #context .tick { 
     stroke:black; 
     stroke-width: 1px; 
     } 
     #context .x .tick { 
     stroke:black; 
     stroke-width: 2px; 
     } 
     .axis path, .axis line { 
     fill: none; 
     stroke: #ddd; 
     stroke-width: 1px; 
     shape-rendering: crispEdges; 
     } 
     .axis path { 
     stroke: #999; 
     stroke-width: 2px; 
     } 
     </style> 
     <script type="text/javascript">//<![CDATA[ 
    var data = [{ 
     Id: "1", 
     Year: 1950, 
     Relevance: 55, 
     Category: "Cat1", 
     SpecFreq: 5, 
     GenFreq: 10 
    }, { 
     Id: "2", 
     Year: 1975, 
     Relevance: 25, 
     Category: "Cat1", 
     SpecFreq: 2, 
     GenFreq: 31 
    }, { 
     Id: "3", 
     Year: 1990, 
     Relevance: 75, 
     Category: "Cat1", 
     SpecFreq: 8, 
     GenFreq: 23 
    }, { 
     Id: "4", 
     Year: 1970, 
     Relevance: 45, 
     Category: "Cat1", 
     SpecFreq: 17, 
     GenFreq: 60 
    }, { 
     Id: "5", 
     Year: 1985, 
     Relevance: 90, 
     Category: "Cat1", 
     SpecFreq: 17, 
     GenFreq: 25 
    }]; 

    $(function() { 
     //dimensions 
     var margin = { 
      top: 5.5, 
      right: 19.5, 
      bottom: 39.5, 
      left: 39.5 
     }; 

     //data domain extents 
     var extentX = d3.extent(data, function (d) { 
      return d.Year; 
     }); 
     var extentY = d3.extent(data, function (d) { 
      return d.Relevance; 
     }); 

     var focusAxisOptions = { 
      x: { 
       ticks: { 
        format: d3.format("d"), 
        size: -1* (500 - margin.top - margin.bottom), 
        ticks: 10 
       }, 
       showLabel: true 
      }, 
      y: { 
       ticks: { 
        format: d3.format(""), 
        size: -1 * (800 - margin.left - margin.right), 
        ticks: 10 
       }, 
       showLabel: true 
      } 
     }; 

     var contextAxisOptions = { 
      x: { 
       ticks: { 
        format: d3.format("d"), 
        size: -1 * (100 - margin.top - margin.bottom), 
        ticks: 10 
       }, 
       showLabel: true 
      }, 
      y: { 
       ticks: { 
        format: "", 
        size: 0, 
        ticks: 0 
       }, 
       showLabel: false 
      } 
     }; 

     var focus = DrawChart(data, margin, 800 - margin.left - margin.right, 500 - margin.top - margin.bottom, extentX, extentY, focusAxisOptions); 
     var context = DrawChart(data, margin, 800 - margin.left - margin.right, 100 - margin.top - margin.bottom, extentX, extentY, contextAxisOptions); 

     MakeContextBrushable(context, focus); 

     MakeFocusZoomable(focus); 
    }); 

    function DrawChart(data, margin, width, height, extentX, extentY, axisOptions) { 

     //pad extents to provide some extra "blank" areas around edge of graph 
     var paddedExtentX = [extentX[0] - 5, extentX[1] +5]; 
     var paddedExtentY = [extentY[0] - 5, extentY[1] +5]; 

     //scales 
     var x = d3.scale.linear().domain(paddedExtentX).range([0, width]); 
     var y = d3.scale.linear().domain(paddedExtentY).range([height, 0]); 
     var radiusMax = .025 * width; 
     var radius = d3.scale.sqrt().domain([0, 100]).range([0, radiusMax]); 
     var color = d3.scale.ordinal().domain(["Cat1", "Cat2", "Cat3"]).range(["#b7b8a0", "#898a72", "#878772"]); 

     //axes 
     var xAxis = d3.svg.axis().scale(x).orient("bottom").tickFormat(axisOptions.x.ticks.format).tickSize(axisOptions.x.ticks.size).ticks(axisOptions.x.ticks.ticks); 
     var yAxis = d3.svg.axis().scale(y).orient("left").tickFormat(axisOptions.y.ticks.format).tickSize(axisOptions.y.ticks.size).ticks(axisOptions.y.ticks.ticks); 

     //create and size svg element 
     var svg = d3.select("#chart").append("svg") 
      .attr("width", width + margin.left + margin.right) 
      .attr("height", height + margin.top + margin.bottom) 
      .style("float", "left") 
      .style("clear", "left"); 

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

     // Add the x-axis. 
     g.append("g") 
      .attr("class", "x axis") 
      .attr("transform", "translate(0," + height + ")") 
      .call(xAxis) 
      .selectAll("text") 
      .style("font-size", "10px") 
      .attr("dy", "1.5em"); 

     // Add the y-axis. 
     g.append("g") 
      .attr("class", "y axis") 
      .call(yAxis) 
      .selectAll("text") 
      .style("font-size", "10px") 
      .attr("dx", "-1em"); 

     // Add the x-axis label. 
     if (axisOptions.x.showLabel) { 
      g.append("text") 
      .attr("class", "x label") 
      .attr("text-anchor", "end") 
      .attr("x", width/2) 
      .attr("y", height + 35) 
      .text(" Year"); 
     } 

     // Add the y-axis label. 
     if (axisOptions.y.showLabel) { 
      g.append("text") 
      .attr("class", "y label") 
      .attr("text-anchor", "end") 
      .attr("x", -1 * height/2) 
      .attr("y", -40) 
      .attr("dy", ".75em") 
      .attr("transform", "rotate(-90)") 
      .text("Relevance"); 
     } 

     //plot genFreq 
     var gGenerally = g.append("g").selectAll("circle") 
      .data(data) 
      .enter().append("circle") 
      .style("fill", function (d) { 
       return color(d.Category); 
      }) 
      .attr("cx", function (d) { 
       return x(d.Year); 
      }) 
      .attr("cy", function (d) { 
       return y(d.Relevance); 
      }) 
      .attr("r", function (d) { 
       return radius(d.GenFreq); 
      }) 
      .append("title") 
      .text(function (d) { 
       return "(" + d.Year + ", " + d.Relevance + ", " + d.GenFreq + ", " + d.SpecFreq + ")"; 
      }); 

     //plot specFreq 
     var gWithin = g.append("g").selectAll("circle") 
      .data(data) 
      .enter().append("circle") 
      .style("fill", function (d) { 
       return "#d6d487"; 
      }) 
      .attr("cx", function (d) { 
       return x(d.Year); 
      }) 
      .attr("cy", function (d) { 
       return y(d.Relevance); 
      }) 
      .attr("r", function (d) { 
       return radius(d.SpecFreq); 
      }) 
      .append("title") 
      .text(function (d) { 
       return "(" + d.Year + ", " + d.Relevance + ", " + d.GenFreq + ", " + d.SpecFreq + ")"; 
      }); 

     var chart = { 
      svg: svg, 
      g: g, 
      x: x, 
      y: y, 
      xAxis: xAxis, 
      yAxis: yAxis 
     } 
     return chart; 
    } 

    function MakeContextBrushable(context, focus) { 
     var brush = d3.svg.brush().x(context.x).y(context.y) 
     .on("brushstart", brushstart) 
     .on("brush", brushmove) 
     .on("brushend", brushend); 

     context.g.append("g") 
     .attr("class", "brush") 
     .call(brush); 

     function brushstart() { 
      context.svg.classed("selecting", true); 
     } 

     function brushmove() { 
      var e = d3.event.target.extent(); 
      var circle = context.svg.selectAll("circle"); 
      circle.classed("selected", function (d) { 
       return e[0][0] <= d["DecisionYear"] && d["DecisionYear"] <= e[1][0] 
      && e[0][1] <= d["Relevance"] && d["Relevance"] <= e[1][1]; 
      }); 
     } 

     function brushend() { 
      context.svg.classed("selecting", !d3.event.target.empty()); 
      if (!d3.event.target.empty()) { 
       var e = d3.event.target.extent(); 
       focus.x.domain([e[0][0], e[1][0]]); 
       focus.y.domain([e[0][1], e[1][1]]); 

       focus.g.select(".x.axis").call(focus.xAxis) 
        .selectAll("text") 
        .style("font-size", "10px") 
        .attr("dx", "-1em"); 
       focus.g.select(".y.axis").call(focus.yAxis) 
        .selectAll("text") 
        .style("font-size", "10px") 
        .attr("dx", "-1em"); 
       var circle = focus.svg.selectAll("circle").attr("cx", function (d) { return focus.x(d.Year); }) 
       .attr("cy", function (d) { return focus.y(d.Relevance); }) 
       console.log("BrushEnd Domain: [" + focus.x.domain()[0] + ", " + focus.x.domain()[1] + "]"); 
      } 
      else { 
       focus.x.domain(context.x.domain()); 
       focus.y.domain(context.y.domain()); 
       focus.g.select(".x.axis").call(focus.xAxis) 
        .selectAll("text") 
        .style("font-size", "10px") 
        .attr("dx", "-1em"); 
       focus.g.select(".y.axis").call(focus.yAxis) 
        .selectAll("text") 
        .style("font-size", "10px") 
        .attr("dx", "-1em"); 
       var circle = focus.g.selectAll("circle").attr("cx", function (d) { return focus.x(d.Year); }) 
       .attr("cy", function (d) { return focus.y(d.Relevance); }) 
      } 
     } 
    } 

    function MakeFocusZoomable(focus) { 
     focus.svg.call(d3.behavior.zoom().x(focus.x).y(focus.y).on("zoom", Zoom)); 

     function Zoom() { 
      focus.svg.select(".x.axis").call(focus.xAxis).selectAll("text") 
         .style("font-size", "10px") 
         .attr("dy", "1.5em"); 

      focus.svg.select(".y.axis").call(focus.yAxis).selectAll("text") 
         .style("font-size", "10px") 
         .attr("dx", "-1em"); 

      focus.svg.selectAll("circle").attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); 
     } 
    } 
     </script> 
    </head> 
    <body> 
     <div id="chart"> 
     </div> 
    </body> 
</html> 

回答

3

要平移復位後刷牙,你就需要重新再喊brush.extent:

//Find extent of zoomed area, for example the edges of graphed region 
var brushExtent = [x.invert(0), x.invert(width)]; 
context.select(".brush").call(brush.extent(brushExtent)); 

這裏的焦點/背景下的一個例子在線圖上刷洗平移同步: http://jsfiddle.net/MtXvx/8/

希望幫助!