Maison  >  Questions et réponses  >  le corps du texte

Les points de nuage de points ne conservent pas leurs valeurs lors du zoom dans d3.js

C'est la première fois que j'utilise d3.js, alors soyez patient. Je l'ai implémenté en JavaScript pur dans un fichier vue.js. J'essaie de créer un nuage de points avec une fonctionnalité de zoom. Jusqu'à présent, presque tout fonctionne bien, mais lorsque je zoome, je remarque que l'axe des x n'est pas mis à l'échelle correctement, mais que l'axe des y fonctionne bien. Par exemple, lorsque vous regardez le graphique d'origine, un point peut se trouver autour de 625 sur l'axe des X, mais le même point sera plus petit que 600 lors d'un zoom avant. Cela ne se produit pas sur l'axe y - les points sont correctement mis à l'échelle. Je suppose qu'il y a quelque chose qui ne va pas avec la mise à l'échelle de l'axe des x dans la fonction de mise à l'échelle, mais je n'arrive pas à le comprendre. S'il vous plaît, jetez un œil et faites-moi savoir si vous voyez où je me trompe.

EDIT : je dois mentionner que cela utilise d3.js version 7.4.4

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

Fait intéressant, le problème a semblé se résoudre de lui-même après avoir défini la zone de découpage pour empêcher l'affichage des points en dehors de l'axe. Voici comment je crée le chemin de détourage :

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

J'ai ensuite ajouté cet attribut au svg lors du traçage des données comme ceci :

svg.append("g").attr("clip-path", "url(#clip)")

Chemin de détourage mis à jour avec la section de données de dessin :

// 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粉294954447P粉294954447194 Il y a quelques jours527

répondre à tous(1)je répondrai

  • P粉659516906

    P粉6595169062024-04-07 15:47:25

    J'ai finalement résolu le problème. J'ai mis à jour le message d'origine pour montrer ce qui a fonctionné pour moi.

    En gros, après avoir ajouté la zone de découpage, tout a commencé à fonctionner correctement.

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

    répondre
    0
  • Annulerrépondre