Heim > Fragen und Antworten > Hauptteil
Ich verwende d3.js zum ersten Mal, also haben Sie bitte etwas Geduld. Ich habe es als reines JavaScript in einer vue.js-Datei implementiert. Ich versuche, ein Streudiagramm mit Zoomfunktion zu erstellen. Bisher funktioniert bei mir fast alles einwandfrei, aber beim Zoomen stelle ich fest, dass die x-Achse nicht richtig skaliert, die y-Achse jedoch einwandfrei. Wenn Sie beispielsweise das Originaldiagramm betrachten, liegt ein Punkt möglicherweise bei etwa 625 auf der x-Achse, beim Vergrößern ist derselbe Punkt jedoch kleiner als 600. Auf der Y-Achse passiert das nicht – die Punkte werden korrekt skaliert. Ich gehe davon aus, dass mit der Skalierung der x-Achse in der Skalierungsfunktion etwas nicht stimmt, aber ich komme einfach nicht dahinter. Bitte werfen Sie einen Blick darauf und lassen Sie mich wissen, ob Sie erkennen können, wo ich falsch liege.
EDIT: Ich sollte erwähnen, dass hier d3.js Version 7.4.4 verwendet wird
<template> <div id="reg_plot"></div> </template> <script> import * as d3 from 'd3'; export default { name: 'regCamGraph', components: { d3 }, methods: { createSvg() { // dimensions var margin = {top: 20, right: 20, bottom: 30, left: 40}, svg_dx = 1400, svg_dy =1000, chart_dx = svg_dx - margin.right - margin.left, chart_dy = svg_dy - margin.top - margin.bottom; // data var y = d3.randomNormal(400, 100); var x_jitter = d3.randomUniform(-100, 1400); var d = d3.range(1000) .map(function() { return [x_jitter(), y()]; }); // fill var colorScale = d3.scaleLinear() .domain(d3.extent(d, function(d) { return d[1]; })) .range([0, 1]); // y position var yScale = d3.scaleLinear() .domain(d3.extent(d, function(d) { return d[1]; })) .range([chart_dy, margin.top]); // x position var xScale = d3.scaleLinear() .domain(d3.extent(d, function(d) { return d[0]; })) .range([margin.right, chart_dx]); console.log("chart_dy: " + chart_dy); console.log("margin.top: " + margin.top); console.log("chart_dx: " + chart_dx); console.log("margin.right: " + margin.right); // y-axis var yAxis = d3.axisLeft(yScale); // x-axis var xAxis = d3.axisBottom(xScale); // zoom var svg = d3.select("#reg_plot") .append("svg") .attr("width", svg_dx) .attr("height", svg_dy); svg.call(d3.zoom().on("zoom", zoom)); // ref [1] // plot data var circles = svg.append("g") .attr("id", "circles") .attr("transform", "translate(200, 0)") .selectAll("circle") .data(d) .enter() .append("circle") .attr("r", 4) .attr("cx", function(d) { return xScale(d[0]); }) .attr("cy", function(d) { return yScale(d[1]); }) .style("fill", function(d) { var norm_color = colorScale(d[1]); return d3.interpolateInferno(norm_color) }); // add y-axis var y_axis = svg.append("g") .attr("id", "y_axis") .attr("transform", "translate(75,0)") .call(yAxis).style("font-size", "20px") // add x-axis var x_axis = svg.append("g") .attr("id", "x_axis") .attr("transform", `translate(${margin.left}, ${svg_dy - margin.bottom})`) .call(xAxis).style("font-size", "20px") function zoom(e) { // re-scale y axis during zoom y_axis.transition() .duration(50) .call(yAxis.scale(e.transform.rescaleY(yScale))); // re-scale x axis during zoom x_axis.transition() .duration(50) .call(xAxis.scale(e.transform.rescaleX(xScale))); // re-draw circles using new y-axis scale var new_xScale = e.transform.rescaleX(xScale); var new_yScale = e.transform.rescaleY(yScale); console.log(d); x_axis.call(xAxis.scale(new_xScale)); y_axis.call(yAxis.scale(new_yScale)); circles.data(d) .attr('cx', function(d) {return new_xScale(d[0])}) .attr('cy', function(d) {return new_yScale(d[1])}); } } }, mounted() { this.createSvg(); } } </script>
Interessanterweise schien sich das Problem von selbst zu lösen, nachdem ich den Beschneidungsbereich so eingestellt hatte, dass Punkte außerhalb der Achse nicht angezeigt werden. So erstelle ich den Beschneidungspfad:
// clip path var clip = svg.append("defs").append("svg:clipPath") .attr("id", "clip") .append("svg:rect") .attr("id", "clip-rect") .attr("x", "0") .attr("y", "0") .attr('width', chart_dx) .attr('height', chart_dy);
Ich habe dieses Attribut dann zum SVG hinzugefügt, als ich die Daten wie folgt dargestellt habe:
svg.append("g").attr("clip-path", "url(#clip)")
Aktualisierter Beschneidungspfad mit Zeichnungsdatenabschnitt:
// clip path var clip = svg.append("defs").append("svg:clipPath") .attr("id", "clip") .append("svg:rect") .attr("id", "clip-rect") .attr("x", "0") .attr("y", "0") .attr('width', chart_dx) .attr('height', chart_dy); // plot data var circles = svg.append("g") .attr("id", "circles") .attr("transform", "translate(75, 0)") .attr("clip-path", "url(#clip)") //added here .selectAll("circle") .data(d) .enter() .append("circle") .attr("r", 4) .attr("cx", function(d) { return xScale(d[0]); }) .attr("cy", function(d) { return yScale(d[1]); }) .style("fill", function(d) { var norm_color = colorScale(d[1]); return d3.interpolateInferno(norm_color) });
P粉6595169062024-04-07 15:47:25
我最终解决了这个问题。我已经更新了原始帖子以展示对我有用的内容。
基本上,添加剪辑区域后,一切开始正常工作。
// clip path (this is the new clip region that I added. It prevents dots from being drawn outside of the axes. var clip = svg.append("defs").append("svg:clipPath") .attr("id", "clip") .append("svg:rect") .attr("id", "clip-rect") .attr("x", "0") .attr("y", "0") .attr('width', chart_dx) .attr('height', chart_dy); // plot data var circles = svg.append("g") .attr("id", "circles") .attr("transform", "translate(75, 0)") .attr("clip-path", "url(#clip)") //added clip region to svg here .selectAll("circle") .data(d) .enter() .append("circle") .attr("r", 4) .attr("cx", function(d) { return xScale(d[0]); }) .attr("cy", function(d) { return yScale(d[1]); }) .style("fill", function(d) { var norm_color = colorScale(d[1]); return d3.interpolateInferno(norm_color) });