Ho costruito un diagramma a dispersione d3.js con funzionalità zoom/panoramica. Si può vedere la cosa completa (clicca 'Apri in una nuova finestra' per vedere il tutto): http://bl.ocks.org/129f64bfa2b0d48d27c9d3.js diagramma a dispersione - zoom/trascinamento confini, pulsanti zoom, reimpostazione zoom, calcolo mediana
ci sono un paio di caratteristiche che sono stato in grado di capire, che mi piacerebbe una mano con esso se qualcuno mi può puntare nella giusta direzione:
- voglio applicare X/Y confini zoom/pan per l'area, in modo che non si può trascinarla sotto un certo punto (ad esempio pari a zero).
- Ho anche provato a creare pulsanti zoom +/- di stile di Google Maps, senza alcun successo. Qualche idea?
Molto meno importante, ci sono anche un paio di aree in cui ho capito una soluzione ma è molto agitato, quindi se avete una soluzione migliore, allora si prega di fare fatemi sapere:
- Ho aggiunto un pulsante 'reset zoom' ma semplicemente elimina il grafico e ne genera uno nuovo al suo posto, piuttosto che lo zoom effettivo degli oggetti. Idealmente dovrebbe effettivamente resettare lo zoom.
Ho scritto la mia funzione per calcolare la mediana dei dati X e Y. Comunque sono sicuro che ci deve essere un modo migliore per farlo con d3.median ma non riesco a capire come farlo funzionare.
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; };
A (cioè vecchia) versione molto semplificata della JS è inferiore. Potete trovare lo script completo al 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)+")";
});
};
}
});
Qualsiasi aiuto sarebbe massicciamente apprezzato. Grazie!
Edit: Ecco un riepilogo delle correzioni che ho usato, sulla base dei suggerimenti di Superboggly qui sotto:
// 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]]);
}
...
};
La traduzione di zoom che ho usato è molto ad hoc e utilizza fondamentalmente costanti abitrary per mantenere il posizionamento più o meno nel posto giusto. Non è l'ideale, e sarei disposto a intrattenere suggerimenti per una tecnica più universalmente valida. Tuttavia, funziona abbastanza bene in questo caso.
Grazie ancora Superboggly! Il tuo codice zoomIn/reset sembra funzionare, ma la scala cambia solo sull'evento di zoom successivo (ad esempio su trascinamento o rotellina del mouse). Sto facendo fatica a far aggiustare le cose al clic del pulsante. Deve essere semplice ma non riesco a capirlo. Il codice di clic del mio pulsante è: d3.select ('# zoomIn'). Call (zoom) .on ('clic', funzione() { d3.event.preventDefault(); zm.scale (zm.scale () * 2); }); Ho provato vari usi di .call(), zoom() e .on() senza alcun risultato. – richardwestenra
Ho aggiunto un piccolo quadratino zoom blu rapido nella parte inferiore del mio [ultimo jsfiddle per te] (http://jsfiddle.net/superboggly/SD5cK/2/). Tutto ciò che ti manca è una chiamata a zoom() dopo aver impostato la scala. Pensa alla funzione di zoom che hai fornito applicando lo stato di zoom calcolato dal comportamento. – Superboggly
okay! Smistato! Si scopre che è esattamente quello che stavo facendo ma non funzionava per me ... Per farla breve: stavi usando d3 versione 3 mentre stavo usando la versione 2, ed è per questo che non ha funzionato quando ho lasciato cadere il tuo quadrato blu nel mio codice. Sono passati alla versione 3 e ora funziona. Saluti :) – richardwestenra