2013-02-25 35 views
6

Yakınlaştırma/kaydırma işleviyle bir d3.js dağılım grafiği oluşturdum. Burada her şeyi görebilirsiniz (her şeyi görmek için 'Yeni bir pencerede aç'a tıklayın): http://bl.ocks.org/129f64bfa2b0d48d27c9d3.js dağılım grafiği - zoom/sürükleme sınırları, zoom düğmeleri, sıfırlama zoom, medyan hesaplayın

Anlayamadığım birkaç özellik var, seveceğim onunla bir el birisi bana doğru yönde işaret edebilir,:

  1. Ben belirli bir noktanın altında sürüklemek değil, böylece bölgeye X/Y yakınlaştırma/pan sınırlarını uygulamak istediğiniz (örneğin sıfır).
  2. Ayrıca, herhangi bir başarı göstermeden Google Haritalar stili +/- zum düğmeleri oluştururken bir bıçak da yaptım. Herhangi bir fikir?

Çok az önemlisi de bir çözüm anladım alanların bir çift vardır ama daha iyi bir çözüm varsa o zaman lütfen bu yüzden bana bildirin, çok kaba:

  1. Bir 'sıfırlama zum' düğmesine ekledim ancak grafikleri siler ve aslında nesneleri yakınlaştırmak yerine yerine yeni bir tane oluşturur. İdeal olarak, zoom'u gerçekten sıfırlamalıdır.
  2. X ve Y verilerinin medyanını hesaplamak için kendi işlevlerimi yazdım. Ancak eminim d3.median ile bunu yapmanın daha iyi bir yolu olmalı, ancak nasıl çalışacağımı anlayamıyorum.

    var xMed = median(_.map(data,function(d){ return d.TotalEmployed2011;})); 
    var yMed = median(_.map(data,function(d){ return d.MedianSalary2011;})); 
    
    function median(values) { 
        values.sort(function(a,b) {return a - b;}); 
        var half = Math.floor(values.length/2); 
    
        if(values.length % 2) 
         return values[half]; 
        else 
         return (parseFloat(values[half-1]) + parseFloat(values[half]))/2.0; 
    }; 
    

JS bir çok basitleştirilmiş bir (yani eski) sürümü altındadır. Sen Herhangi bir yardım kitlesel mutluluk duyacağız https://gist.github.com/richardwestenra/129f64bfa2b0d48d27c9#file-main-js

d3.csv("js/AllOccupations.csv", function(data) { 

    var margin = {top: 30, right: 10, bottom: 50, left: 60}, 
     width = 960 - margin.left - margin.right, 
     height = 500 - margin.top - margin.bottom; 

    var xMax = d3.max(data, function(d) { return +d.TotalEmployed2011; }), 
     xMin = 0, 
     yMax = d3.max(data, function(d) { return +d.MedianSalary2011; }), 
     yMin = 0; 

    //Define scales 
    var x = d3.scale.linear() 
     .domain([xMin, xMax]) 
     .range([0, width]); 

    var y = d3.scale.linear() 
     .domain([yMin, yMax]) 
     .range([height, 0]); 

    var colourScale = function(val){ 
     var colours = ['#9d3d38','#c5653a','#f9b743','#9bd6d7']; 
     if (val > 30) { 
      return colours[0]; 
     } else if (val > 10) { 
      return colours[1]; 
     } else if (val > 0) { 
      return colours[2]; 
     } else { 
      return colours[3]; 
     } 
    }; 


    //Define X axis 
    var xAxis = d3.svg.axis() 
     .scale(x) 
     .orient("bottom") 
     .tickSize(-height) 
     .tickFormat(d3.format("s")); 

    //Define Y axis 
    var yAxis = d3.svg.axis() 
     .scale(y) 
     .orient("left") 
     .ticks(5) 
     .tickSize(-width) 
     .tickFormat(d3.format("s")); 

    var svg = d3.select("#chart").append("svg") 
     .attr("width", width + margin.left + margin.right) 
     .attr("height", height + margin.top + margin.bottom) 
     .append("g") 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
     .call(d3.behavior.zoom().x(x).y(y).scaleExtent([1, 8]).on("zoom", zoom)); 

    svg.append("rect") 
     .attr("width", width) 
     .attr("height", height); 

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

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

    // Create points 
    svg.selectAll("polygon") 
     .data(data) 
     .enter() 
     .append("polygon") 
     .attr("transform", function(d, i) { 
      return "translate("+x(d.TotalEmployed2011)+","+y(d.MedianSalary2011)+")"; 
     }) 
     .attr('points','4.569,2.637 0,5.276 -4.569,2.637 -4.569,-2.637 0,-5.276 4.569,-2.637') 
     .attr("opacity","0.8") 
     .attr("fill",function(d) { 
      return colourScale(d.ProjectedGrowth2020); 
     }); 

    // Create X Axis label 
    svg.append("text") 
     .attr("class", "x label") 
     .attr("text-anchor", "end") 
     .attr("x", width) 
     .attr("y", height + margin.bottom - 10) 
     .text("Total Employment in 2011"); 

    // Create Y Axis label 
    svg.append("text") 
     .attr("class", "y label") 
     .attr("text-anchor", "end") 
     .attr("y", -margin.left) 
     .attr("x", 0) 
     .attr("dy", ".75em") 
     .attr("transform", "rotate(-90)") 
     .text("Median Annual Salary in 2011 ($)"); 


    function zoom() { 
     svg.select(".x.axis").call(xAxis); 
     svg.select(".y.axis").call(yAxis); 
     svg.selectAll("polygon") 
      .attr("transform", function(d) { 
       return "translate("+x(d.TotalEmployed2011)+","+y(d.MedianSalary2011)+")"; 
      }); 
    }; 
    } 
}); 

tam komut dosyası bulabilirsiniz. Teşekkürler!

Düzenleme: İşte aşağıda Superboggly önerilerine göre kullandığım düzeltmeler bir özetidir:

// Zoom in/out buttons: 
    d3.select('#zoomIn').on('click',function(){ 
     d3.event.preventDefault(); 
     if (zm.scale()< maxScale) { 
      zm.translate([trans(0,-10),trans(1,-350)]); 
      zm.scale(zm.scale()*2); 
      zoom(); 
     } 
    }); 
    d3.select('#zoomOut').on('click',function(){ 
     d3.event.preventDefault(); 
     if (zm.scale()> minScale) { 
      zm.scale(zm.scale()*0.5); 
      zm.translate([trans(0,10),trans(1,350)]); 
      zoom(); 
     } 
    }); 
    // Reset zoom button: 
    d3.select('#zoomReset').on('click',function(){ 
     d3.event.preventDefault(); 
     zm.scale(1); 
     zm.translate([0,0]); 
     zoom(); 
    }); 


    function zoom() { 

     // To restrict translation to 0 value 
     if(y.domain()[0] < 0 && x.domain()[0] < 0) { 
      zm.translate([0, height * (1 - zm.scale())]); 
     } else if(y.domain()[0] < 0) { 
      zm.translate([d3.event.translate[0], height * (1 - zm.scale())]); 
     } else if(x.domain()[0] < 0) { 
      zm.translate([0, d3.event.translate[1]]); 
     } 
     ... 
    }; 

kullandığım yakınlaştırma çeviri çok özel olduğunu ve temelde daha konumlandırma tutmaya abitrary sabitleri kullanan veya Doğru yerde daha az. İdeal değildir ve daha evrensel bir ses tekniği için önerilerde bulunmak isterim. Ancak, bu durumda yeterince iyi çalışır.

cevap

11

Medyan işleviyle başlamak için yalnızca bir dizi ve isteğe bağlı bir erişimci gerekir. Eğer yakınlaştırma davranışını çekin eğer biraz daha iyi kontrol edebilir Diğerlerine gelince

var med = d3.median(data, function(d) { return +d.TotalEmployed2011; }); 

: Yani Eğer max kullandığınız şekilde kullanabilirsiniz.

var zm = d3.behavior.zoom().x(x).y(y).scaleExtent([1, 8]).on("zoom", zoom); 
var svg = d3.select()...call(zm); 

Sonra doğrudan yakınlaştırma düzeyini ve çeviriyi ayarlayabilirsiniz: deneyin

var svg = d3.select()...call(d3.behavior.zoom()...) 

örneğin yerine

Yani

function zoomIn() { 
    zm.scale(zm.scale()*2); 
    // probably need to compute a new translation also 
} 

function reset() { 
    zm.scale(1); 
    zm.translate([0,0]); 
} 

kaydırma aralığı kısıtlama biraz daha zordur.Tercüme veya ölçek, size yakınlaştırma fonksiyonunun içinde hoşunuza gitmediğinde güncellenemez (ya da yakınlaştırmanın "çevirisini" gerek duyduğunuz şekilde). gibi bir şey (sizin durumunuzda düşünüyorum):

function zoom() { 
    if(y.domain()[0] < 0) { 
     // To restrict translation to 0 value 
     zm.translate([d3.event.translate[0], height * (1 - zm.scale())]); 
    } 
    .... 
}   

Eğer eksen üzerinde olumsuz izin yakınlaştırma, ama sana değil kaydırma istediğiniz eğer biraz zor senaryolar içine almak bulacaksınız unutmayın.

Bu tarihli ama yakınlaştırma davranışı yatay kaydırmayı kısıtlayarak ve one point ölçeklendirmeue için özelliğe sahip ki aynı zamanda Limiting domain when zooming or panning in D3.js

Not kontrol edilebilir. Ancak kod daha sonra bir update'da alındı.

+0

Tekrar teşekkürler Superboggly! ZoomIn/reset kodunuz çalışıyor gibi görünüyor, ancak ölçek sadece bir sonraki yakınlaştırma etkinliğinde (yani, sürükleme veya mousewheel'de) değişir. Düğme tıklaması ile ilgili güncellemeleri almak için zor bir zaman geçiriyorum. Basit olmalı ama anlayamıyorum. Düğme tıklatma kodum: d3.select ('# zoomIn') Ara (yakınlaştırma) .on ('click', işlev() { d3.event.preventDefault(); zm.scale (zm.scale () * 2) }); Çeşitli .call(), zoom() ve .on() kullanımlarını hiçbir şekilde kullanamaya çalıştım. – richardwestenra

+0

[Senin için son jsfiddle] 'un altında bir hızlı küçük mavi yakınlaştırma karesi ekledim (http://jsfiddle.net/superboggly/SD5cK/2/). Eksik olan tek şey, ölçeği ayarladıktan sonra zoom() için bir çağrıdır. Sağladığınız yakınlaştırma işlevini, davranış tarafından hesaplanan yakınlaştırma durumunu uygulayarak düşünün. – Superboggly

+0

tamam! Sıralama! Bu benim yaptığım işin tam tersi oldu, ama benim için çalışmadı ... Uzun hikaye kısa: Ben sürüm 2 kullanırken d3 sürüm 3 kullanıyordunuz ve bu yüzden ben düştüğümde işe yaramadı. kodumda mavi kare. V3'e yükseltin ve şimdi çalışıyor. Şerefe :) – richardwestenra

-1

Tekerleği yeniden icat etmeyi sevmiyorum. Yakınlaştırmaya izin veren dağınık araziler arıyordum. Highcharts bunlardan biri, ama D3 dayanan ve sadece yakınlaştırma izin değil, aynı zamanda ben de veri kümeleri bazı ile arzuluyorum dağınık arsa üzerinde çizgi veri kümeleri olabilir, ve başka ile bulmak zor arsa kütüphaneleri. zaman ve acı bir sürü kaydedebilirsiniz böyle güzel kütüphaneyi kullanma

https://plot.ly/javascript/line-and-scatter/

https://github.com/plotly/plotly.js

: Ben bir deneyin verirdim.