d3.js scatter-plot - zoom/Grenzen ziehen, zoom-Tasten, reset-zoom, median berechnen
Habe ich gebaut d3.js scatter-plot mit zoom - /pan-Funktionen. Sie können die vollständige Sache, die hier (klicken Sie auf 'Öffnen in einem neuen Fenster" zu sehen, die ganze Sache):
http://bl.ocks.org/129f64bfa2b0d48d27c9
Gibt es ein paar features, die ich habe nicht in der Lage herauszufinden, dass ich würde gerne eine hand, wenn jemand kann mich in die richtige Richtung:
- Ich möchte die X/Y-zoom - /pan-Grenzen, um den Bereich, so dass Sie nicht ziehen Sie es unter einem bestimmten Punkt (z.B. null).
- Ich habe aber auch einen stab zu schaffen, Google-Maps-Stil +/- zoom Knöpfe, ohne Erfolg. Irgendwelche Ideen?
Viel weniger wichtig ist, es gibt auch ein paar Bereiche, wo ich herausgefunden haben, eine Lösung aber es ist sehr rau, so dass, wenn Sie eine bessere Lösung, dann bitte lass es mich wissen:
- Ich habe ein 'reset zoom' - Taste, sondern lediglich, löscht den Graphen und generiert eine neue an deren Stelle, sondern tatsächlich durch das Zoomen der Objekte. Im Idealfall sollte es eigentlich den zoom rückgängig zu machen.
-
Ich geschrieben habe meine eigene Funktion berechnet den Mittelwert der X-und Y-Daten. Aber ich bin sicher, es muss einen besseren Weg, dies zu tun mit d3.median, aber ich kann nicht herausfinden, wie es funktioniert.
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; };
Einer sehr vereinfachten (d.h. alte) version der JS ist unten. Sie finden das vollständige Skript an 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)+")";
});
};
}
});
Jede Hilfe würde Massiv geschätzt. Danke!
Edit: Hier ist eine Zusammenfassung der fixes, die ich verwendet, basierend auf Superboggly Anregungen unter:
//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]]);
}
...
};
Den zoom-übersetzung, die ich verwendet, ist sehr ad hoc und im Grunde verwendet, frei wählbare Konstanten halten der Positionierung mehr oder weniger in der richtigen Stelle. Es ist nicht ideal, und ich würde bereit sein, zu unterhalten, Anregungen für einen mehr allgemein Ton-Technik. Aber es funktioniert gut genug, in diesem Fall.
InformationsquelleAutor richardwestenra | 2013-02-25
Du musst angemeldet sein, um einen Kommentar abzugeben.
Starten, um mit der median-Funktion nimmt ein array und ein optionales accessor. So können Sie es verwenden die gleiche Weise, die Sie verwenden, max:
Als für die anderen, wenn Sie aus ziehen Sie Ihre zoom-Verhalten können Sie Steuern, es ein bisschen besser. Also zum Beispiel statt
versuchen:
Dann können Sie die zoom-Stufe und die übersetzung direkt:
Einschränkung der panning-Bereich ist ein bisschen schwieriger. Sie können einfach nicht aktualisiert, wenn das übersetzen oder die Skala ist nicht nach Ihrem Geschmack im inneren zoom-Funktion (oder das zoom "übersetzen", was Sie brauchen, es zu sein). Sowas wie (ich denke in deinem Fall):
Beachten Sie, dass wenn Sie möchten, Zoomen zu erlauben, eine negative auf der Achse, aber das panning nicht zu finden Sie erhalten Sie in einige knifflige Szenarien.
Dies kann datiert werden, aber überprüfen Sie heraus Begrenzung der domain-beim Zoomen oder schwenken in D3.js
Beachten Sie auch, dass das zoom-Verhalten hat-Funktionalität für die Begrenzung schwenken und Zoomen auf einen Punkt. Aber der code wurde in einem späteren update.
Ich habe eine schnelle kleine Blaue zoom-Platz an der Unterseite von meinem Letzte jsfiddle für Sie. Alles, was Sie fehlt, ist der Aufruf von zoom() nachdem Sie festgelegt haben, die Waage. Denke der zoom-Funktion, die Sie geliefert haben, als die Anwendung der zoom-Zustand, berechnet aus dem Verhalten.
okay! Sortiert! Es stellt sich heraus, dass das ist genau das, was ich Tat, aber es war nicht für mich arbeiten... Lange Geschichte kurz: Sie wurden mit d3 version 3, während ich war mit version 2, und das ist, warum es nicht funktioniert, wenn ich ließ das Blaue Quadrat in meinem code. Haben ein Upgrade auf v3 und es funktioniert jetzt. Prost 🙂
Ah gut zu wissen! Ich wusste, dass Sie schrieb das zoom-Verhalten aber ich glaube nicht, Versionen überprüfen!
Keine sorgen :). Übrigens, ich habe ziemlich viel versendet es jetzt, aber für zukünftige Referenz (im Fall, dass jemand stolpert über diese Seite und will wissen wie ich es gemacht habe oder kann Verbesserungen vorschlagen): ich hatte ein bisschen Mühe die Berechnung der übersetzen-Funktion, so landete ich schlug in einer willkürlichen Konstanten. Es scheint zu funktionieren gut genug: Funktion trans(xy,Konstante){ return zm.translate()[xy]+(Konstante*(zm.scale())); } zm.translate([trans(0,-10),trans - (1,-350)]);
InformationsquelleAutor Superboggly
Mag ich nicht, das Rad neu zu erfinden. Ich war auf der Suche nach scatter-plots, die es erlauben Zoomen. Highcharts ist einer von Ihnen, aber es gibt plotly, basierend auf D3 und ermöglicht nicht nur das Zoomen, aber Sie können auch line-datasets auch in der scatter-plot, das Wünsche ich einige meiner Datensätze, und das ist schwer zu finden, mit anderen plot-Bibliotheken. Ich würde es versuchen:
https://plot.ly/javascript/line-and-scatter/
https://github.com/plotly/plotly.js
Verwendung solcher schönen Bibliothek können Sie sparen eine Menge Zeit und Schmerzen.
InformationsquelleAutor Csaba Toth