2013-03-22 162 views
33

好吧,我開始對D3稍微熟悉一些,但在某些事情上我仍然有點朦朧。我現在正在試圖畫出網格線,但我意識到我可能會剽竊而不是正確地做。我嘗試添加一些網格線,使用教程,但最終得到了很多代碼,我似乎是爲了使它正確排列而進行綁定。我想知道是否有人可以指點我一個更好的寫作方式...繪製網格線的正確方法

原始代碼是這樣的。

 <script type="text/javascript"> 

      //Width and height 
      var w = 800; 
      var h = 400; 
      var padding = 20; 
      var border=1; 
      var bordercolor='black'; 


      var dataset = [ 
          [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],[-50,-100],[50,-45], 
          [410, 12], [475, 44], [25, 67], [85, 21], [220, 88],[-480, -467], [3,-90],[468,481] 
          ]; 

       // create scale functions 
       var xScale = d3.scale.linear() 
           .domain([d3.min(dataset, function(d) { return d[0]; }), d3.max(dataset, function(d) { return d[0]; })]) 
           .range([padding, w - padding * 2]); 

      var yScale = d3.scale.linear() 
           .domain([d3.min(dataset, function(d) { return d[0]; }), d3.max(dataset, function(d) { return d[1]; })]) 
           .range([h - padding, padding]); 

       var rScale = d3.scale.linear() 
       .domain( [-100,  d3.max(dataset, function(d) { return d[1];   })] ) 
       .range([2,5]); 

      //Create SVG element 
      var svg = d3.select("body") 
         .append("svg") 
         .attr("width", w) 
         .attr("height", h) 
         .attr("border",border) 
         ; 

      //define X axis this is rly a function, remember, variables can hold functions in JS 
       var xAxis = d3.svg.axis() 
         .scale(xScale) 
         .orient("bottom") 
         .ticks(1) 
         .tickSize(-h, 0, 0) 
         ; //Set rough # of ticks 


      //Define Y axis 
       var yAxis = d3.svg.axis() 
         .scale(yScale) 
         .orient("left") 
         .ticks(1) 
         .tickSize(-w, 0, 0) 
         ; 




       //create the circles 
      svg.selectAll("circle") 
       .data(dataset) 
       .enter() 
       .append("circle") 
       .attr("cx", function(d) { 
        return xScale(d[0]); 
       }) 
       .attr("cy", function(d) { 
        return yScale(d[1]); 
       }) 
       .attr("r", 3); 





    // draw axes here 
    svg.append("g") 
    .attr("class", "axis") //assign "axis" class 
    .attr("transform", "translate(0," + (h - padding) +")") 
    .call(xAxis); 



     svg.append("g") 
    .attr("class", "axis") //assign "axis" class 
    .attr("transform", "translate(" + padding + ",0)"  ) 
    .call(yAxis); 
// end draw axes here 
     </script> 

,我在第二個環節添加的代碼是在這裏

var vis = svg.append("svg:g") 
    .attr("transform", "translate(20,0)") 


var rules = vis.append("svg:g").classed("rules", true) 


rules.append("svg:g").classed("grid x_grid", true) 
    .attr("transform", "translate(-20,"+h+")") 
    .call(d3.svg.axis() 
     .scale(xScale) 
     .orient("bottom") 
     .ticks(4) 
     .tickSize(-h,0,0) 
     .tickFormat("") 
    ) 

rules.append("svg:g").classed("grid y_grid", true) 
    .call(d3.svg.axis() 
     .scale(yScale) 
     .orient("left") 
     .ticks(5) 
     .tickSize(-w,0,0) 
     .tickFormat("") 
    ) 

rules.append("svg:g").classed("labels x_labels", true) 
    .attr("transform", "translate(-20,"+ h +")") 
    .call(d3.svg.axis() 
     .scale(xScale) 
     .orient("bottom") 
     .ticks(4) 
     .tickSize(0) 
      .tickFormat("") 
     // .tickFormat(d3.time.format("%Y/%m")) 
    ) 

rules.append("svg:g").classed("labels y_labels", true) 
    .call(d3.svg.axis() 
     .scale(yScale) 
     .orient("left") 
     .ticks(5) 
     .tickSubdivide(1) 
     .tickSize(0, 0, 0) 
      .tickFormat("") 
    ) 

再次,非常感謝所有幫助

回答

11

你可以使用你的規模ticks()函數來獲取刻度值和然後在數據調用中使用它們來繪製線條。

var ticks = xScale.ticks(4); 
rules.selectAll("path.xgrid").data(ticks).enter() 
    .append("path") 
    .attr("d", function(d) { 
     return "M" + xScale(d) + " " + padding + "L" + xScale(d) + " " + (h-padding); 
    }); 

您可能更喜歡對網格線使用線條生成器,而不是手動創建路徑。這對於y個網格線類似地工作,只是y座標是常數並且範圍從0到圖的寬度。您可能需要調整開始和結束值以使其看起來「很好」。

+1

我同意拉爾斯,並發現使用網格線的蜱也很有用。在這裏查看變體http://www.d3noob.org/2013/01/adding-grid-lines-to-d3js-graph.html – d3noob 2013-03-23 01:52:33

+0

這是我用來創建我的圖形的這個版本的鏈接:http:/ /goo.gl/OmX52,但我最終不得不手動弄亂「變換」以使線條匹配,但它仍然不完美。拉爾斯,我將你的代碼複製到我的

61

假設您已經定義了Mike Bostock's標準margins,並且您已經爲y軸定義了線性比例,則以下代碼將創建水平網格線而不使用tickSize()

svg.selectAll("line.horizontalGrid").data(yScale.ticks(4)).enter() 
    .append("line") 
     .attr(
     { 
      "class":"horizontalGrid", 
      "x1" : margin.right, 
      "x2" : width, 
      "y1" : function(d){ return yScale(d);}, 
      "y2" : function(d){ return yScale(d);}, 
      "fill" : "none", 
      "shape-rendering" : "crispEdges", 
      "stroke" : "black", 
      "stroke-width" : "1px" 
     }); 
+5

謝謝!我不知道我們可以一起宣佈許多attr – muyueh 2013-11-29 03:07:42

+5

絕對!這個單一的屬性對象也可以用於.style({...}) – arete 2013-12-22 22:32:40

+0

您是否介意解釋您不使用Ticksize背後的動機,以及爲什麼您的解決方案可能被認爲是更好的練習? – Seanny123 2014-10-27 15:07:37

16

我會建議使用d3.svg.axis()。scale()將網格綁定到您的座標。我根據你的代碼畫了一個quick examplehttp://jsfiddle.net/temirov/Rt65L/1/

Grid example

要點是使用現有的秤,x和y,並利用蜱爲網格。由於yAxis和xAxis已經定義,我們可以重新使用它們。下面是相關代碼:

//Draw a grid 
var numberOfTicks = 6; 

var yAxisGrid = yAxis.ticks(numberOfTicks) 
    .tickSize(w, 0) 
    .tickFormat("") 
    .orient("right"); 

var xAxisGrid = xAxis.ticks(numberOfTicks) 
    .tickSize(-h, 0) 
    .tickFormat("") 
    .orient("top"); 

svg.append("g") 
    .classed('y', true) 
    .classed('grid', true) 
    .call(yAxisGrid); 

svg.append("g") 
    .classed('x', true) 
    .classed('grid', true) 
    .call(xAxisGrid); 
+3

+1這是defo最好的方法,因爲這意味着如果您更改座標軸上的.ticks()屬性,那麼它會反映在網格線上。 – ninjaPixel 2015-01-31 15:15:39

1

繼@美德的想法,你可以使用以下,以避免重新繪製不必要的網格線:

function createsGrid(data) { 
     var grid = gridLine.selectAll("line.horizontalGrid").data(scaleY.ticks()); 

     grid.enter() 
     .append("line") 
     .attr("class","horizontalGrid"); 

     grid.exit().remove(); 

     grid.attr({ 
       "x1":0, 
       "x2": width, 
       "y1": function (d) { return scaleY(d); }, 
       "y2": function (d) { return scaleY(d); } 
       }); 
} 

,並定義在CSS文件中的以下

line.horizonalGrid{ 
    fill : none; 
shape-rendering : crispEdges; 
stroke : black; 
stroke-width : 1.5px; 
} 
0

您可以使用innerTickSize而不是tickSize:

  var xAxis = d3.svg.axis() 
        .scale(xScale) 
        .orient("bottom") 
        .ticks(1) 
        .innerTickSize(-h); 
1

在d3fc項目中,我們創建了一個gridlines component,其渲染方式與D3(v4)軸完全相同。

這裏的使用的例子:

var width = 500, height = 250; 
var container = d3.select("#gridlines") 
    .append("svg") 
    .attr("width", width) 
    .attr("height", height); 

var xScale = d3.scaleLinear() 
    .range([0, 100]); 

var yScale = d3.scaleLinear() 
    .range([0, 100]); 

var gridline = fc.annotationSvgGridline() 
    .xScale(xScale) 
    .yScale(yScale); 

container.append("g") 
    .call(gridline); 

這使得如下:

enter image description here

網格線的間距由通過關聯軸供給蜱確定。

披露:我是d3fc項目的核心貢獻者!