web-dev-qa-db-fra.com

Comment mettre à jour un chemin svg avec d3.js

Je voudrais appliquer le "modèle de mise à jour général" de la documentation officielle pour mettre à jour un chemin svg sur l'événement de la souris (mais cela pourrait être un bouton ou autre).

Mais le chemin est seulement ajouté et non mis à jour. Je pense que c'est pourquoi je n'utilise pas correctement les propriétés enter et exit mais après plusieurs essais, je n'arrive pas à le laisser fonctionner.

Voici un jsfiddle .

Mon code js est ici:

var shapeCoords = [
                  [10, 10], [100, 10], [100, 100], [10, 100]                  
                  ];

$(function() {
    var container = $('#container');

    // D3
    console.log("D3: ", d3);

    var svg = d3.select('#container')
                .append('svg:svg')
                .attr('height', 600)
                .attr('width', 800);

    var line = d3.svg.line()
                    .x(function(d) { return d[0]; })
                    .y(function(d) { return d[1]; })
                    .interpolate('linear');

    function render() {

            svg.data(shapeCoords)
                .append('svg:path')
                .attr('d', line(shapeCoords) + 'Z')
                .style('stroke-width', 1)
                .style('stroke', 'steelblue');
    }
    render();

    var mouseIsDown = false;  
    container.on('mousedown mouseup mousemove', function(e) {
        if (e.type == 'mousedown') {
            mouseIsDown = true; 
            shapeCoords[3] = [e.offsetX, e.offsetY];
        } else if (e.type == 'mouseup' ){
            mouseIsDown = false;
            shapeCoords[3] = [e.offsetX, e.offsetY];
        } else if (e.type == 'mousemove') {
            if (mouseIsDown) {
                shapeCoords[3] = [e.offsetX, e.offsetY];
                render();
            }
        }
    });


});

Et le html:

<!DOCTYPE html>
<html>
<head>
    <title>D3 mousemove</title>
    <script type="text/javascript" 
            src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
    </script>
    <script type="text/javascript" 
            src="http://mbostock.github.com/d3/d3.js">
    </script>
    <script type="text/javascript" src="script.js"></script>
    <style>
        #container { 
            width: 800px; 
            height: 600px; 
            border: 1px solid silver; }
        path, line {
            stroke: steelblue;
            stroke-width: 1;
            fill: none;
        }
    </style>
</head> 
<body>   
    <div id="container"></div>
</body>
</html>
17
nkint

Votre code ne sélectionne pas un élément existant, donc au lieu de mettre à jour l'attribut "d" d'un chemin existant via la sélection update, il ajoute un nouveau chemin à chaque fois. Cette version de render() a produit le comportement attendu. Plus d'informations sur les sélections ici .

function render() {
    path = svg.selectAll('path').data([shapeCoords])
    path.attr('d', function(d){return line(d) + 'Z'})
        .style('stroke-width', 1)
        .style('stroke', 'steelblue');
    path.enter().append('svg:path').attr('d', function(d){return line(d) + 'Z'})
        .style('stroke-width', 1)
        .style('stroke', 'steelblue');
    path.exit().remove()

Une fois que vous avez exécuté la jointure de données sur path via .data(), les opérations effectuées sur path ne s'appliqueront qu'à la sélection de mise à jour. Cela signifie que seuls les éléments existants qui ont encore des éléments de données correspondants sous la nouvelle jointure. Lorsque vous appelez enter().append(), il ajoutera un nouvel élément pour chaque élément de données sans élément préexistant, puis appliquera les opérations suivantes uniquement à ces éléments.

Dans ce qui précède, la première path.attr() ci-dessus ne fonctionne que sur les éléments existants; ceux appliqués après path.enter() ne s'appliquent qu'aux nouveaux éléments. Il n'est pas présenté dans l'extrait ci-dessus, mais enter() ajoute la sélection d'entrée à la sélection de mise à jour: toutes les opérations sur path après avoir appelé enter() s'appliqueraient à la fois à l'existant et au nouveau éléments.

14
Sean Easter

Veuillez essayer le code suivant, je pense que c'est ce que vous voulez. Le problème est dû au fait que vous devez distinguer entre, mettre à jour et quitter lorsque vous souhaitez mettre à jour des éléments, sinon il ajoutera des données encore et encore.

$(function() {
var container = $('#container');

// D3
console.log("D3: ", d3);

var svg = d3.select('#container')
            .append('svg:svg')
            .attr('height', 600)
            .attr('width', 800);

var line = d3.svg.line()
                .x(function(d) { return d[0]; })
                .y(function(d) { return d[1]; })
                .interpolate('linear');

svg.data(shapeCoords)
    .append('svg:path')
    .attr('d', line(shapeCoords) + 'Z')
    .style('stroke-width', 1)
    .style('stroke', 'steelblue');

function render() {

    var svg = d3.select('#container').select("svg").selectAll('path').data(shapeCoords);
    svg.enter().append('svg:path')
            .attr('d', line(shapeCoords) + 'Z')
            .style('stroke-width', 1)
            .style('stroke', 'steelblue');
    svg.attr('d', line(shapeCoords) + 'Z')
            .style('stroke-width', 1)
            .style('stroke', 'steelblue');    
    svg.exit().remove();    

}
render();
4
linpingta