2013-03-22 16 views
33

Dobra, zaczynam poznawać nieco D3, ale wciąż mam pewne wątpliwości. Teraz próbuję narysować linie siatki, ale zdaję sobie sprawę, że mogę się odhakować, zamiast robić to poprawnie. Próbowałem dodać kilka linii siatki, używając samouczka, ale skończyło się na tym, że mam sporo kodu, który wydaje się być olimpisem jimmy, aby poprawnie ustawić linię. Zastanawiam się, czy ktoś mógłby wskazać mi na lepszy sposób napisania tego ...Prawidłowy sposób rysowania linii siatki

Oryginalny kod to.

 <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> 

a kod dodałem w drugim linku jest tutaj

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("") 
    ) 

Ponownie, naprawdę wdzięczni za każdą pomoc

Odpowiedz

11

Można użyć funkcji ticks() swojej skali, aby uzyskać wartości podziałki i następnie użyj ich w połączeniu danych, aby narysować linie.

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); 
    }); 

Możesz preferować użycie linii do linii siatki, zamiast tworzyć ścieżkę ręcznie. Działa to podobnie dla linii siatki y, tylko że współrzędna y jest stała i mieści się w zakresie od 0 do szerokości wykresu. Konieczne może być dostosowanie wartości początkowej i końcowej, aby wyglądały "ładnie".

+1

Zgadzam się z Larsem i stwierdziłem, że używanie znaczników dla linii siatki jest również użyteczne. Zobacz tutaj dla wariantu http://www.d3noob.org/2013/01/adding-grid-lines-to-d3js-graph.html – d3noob

+0

To był link, którego użyłem do stworzenia tej wersji mojego wykresu: http://goo.gl/OmX52, ale skończyło się na tym, że musiałem ręcznie pomieszać z "transformacją", aby dopasować linie i nadal nie było idealnie w linii. Lars, skopiowałem twój kod do mojego

61

Zakładając, że ma Mike Bostock's średnia margins określono i zdefiniowano w skali liniowej na osi y następujący kod tworzenia poziomych linii siatki bez użycia 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

Dzięki! Nie wiedziałem, że możemy zadeklarować wiele attr razem – muyueh

+5

Absolutnie! Ten pojedynczy obiekt atrybutu może być również użyty z .style ({...}) – arete

+0

Czy mógłbyś wyjaśnić swoją motywację, aby nie używać Ticksize i dlaczego Twoje rozwiązanie może być uważane za lepszą praktykę? – Seanny123

16

Proponuję użyć d3.svg.axis(). Scale(), aby związać siatkę ze współrzędnymi. Narysowałem quick example oparty na kodzie: http://jsfiddle.net/temirov/Rt65L/1/

Grid example

Istotą jest wykorzystanie istniejących skal, X i Y, a użycie kleszczy jako siatki. Ponieważ yAxis i xAxis są już zdefiniowane, możemy je ponownie wykorzystać. Oto odpowiedni kod:

//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 To jest defo najlepszy sposób, aby to zrobić, ponieważ oznacza to, że jeśli zmienisz właściwość .ticks() na swojej osi , zostanie to odzwierciedlone w liniach siatki. – ninjaPixel

1

Po @ idei Arete, można korzystać z następujących czynności, aby uniknąć ponownego rysowania niepotrzebnie linii siatki:

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); } 
       }); 
} 

i określ następujące ustawienia w pliku CSS

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

mógłby po prostu użyć innerTickSize zamiast TickSize:

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

W projekcie d3fc stworzyliśmy gridlines component, który renderuje dokładnie w ten sam sposób, co oś D3 (v4).

Poniżej przedstawiono przykład użycia:

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); 

który powoduje, jak następujące:

enter image description here

Odstęp linii siatki jest określana przez kleszcze dostarczanych przez związanych osi.

Ujawnienie: Jestem głównym uczestnikiem projektu d3fc!

Powiązane problemy