Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.js update pattern not working as expected

I wrote a little lightbox in D3 v4 where on click three images are loaded: the selected one, previous and next in group.

I'm storing references to these images in an array used with the general update pattern. Then, upon clicking the 'previous' or 'next' buttons the array is modified so that one image is added and one removed at either end:

[image1, image2, image3] > 'next' > [image2, image3, image4]

[image1, image2, image3] > 'prev' > [image99, image1, image2]

In other words, one image should 'exit', two should 'update' and one should 'enter'. Visually, it should look like this:

Update pattern after clicking 'next'

Unfortunately, it doesn't work as designed and I'm not sure why. In console, I'm seeing two 'exits', one 'update' and two 'enters'. Why?

Here's my pen and the relevant chunk of code is below. Appreciate any help with this.

d3.selectAll( 'div[role="img"]' ) // image group for lightbox
    .on( "mousedown touchstart", function( d, i, n ) {
        luxBox( d, i, n );
    });

function luxBox( d, idx, n ) {

    var l = n.length,
        j = idx, //selected image in group
        jp = j > 0 ? j - 1 : l - 1, //preceding image in group
        jn = j < l - 1 ? j + 1 : 0; //following image in group

    var imgs = [
        d3.select(n[jp]), //0 
        d3.select(n[j]),  //1
        d3.select(n[jn])  //2
    ];

    function update(data) {

        var t = d3.transition().duration(400);

        var lux = d3.select('#luxbox')
            .attr("class", "show")
            .select('#slider')
            .selectAll('li')
            .data(data, function(d) { return d; }); //join

        lux //exit
            .exit()
            .attr("class", "exit")
            .transition(t)
            .style("opacity", function(d, i) { 
                console.log('exit: i=' + i);
                return 0; 
            })
            .remove();

        lux //update
            .attr("class", "update")
            .transition(t)
            .style("transform", function(d, i) { 
                console.log( 'update: i=' + i );
                return "translateX(" + (i * 100 - 100) + "%)"; 
            });

        lux //enter
            .enter()
            .append('li')
            .attr("class", "enter")
            .style("opacity", 0)
            .style("background-image", function(d) { return d.style('background-image'); })
            .style("transform", function(d, i) { 
                console.log( 'enter: i=' + i );
                return "translateX(" + (i * 100 - 100) + "%)"; 
            })
            //append("h3") // caption
            .transition(t)
            .style("opacity", 1);
    }

    update(imgs);

    d3.select(".next")
        .on("mousedown touchstart", function() { 
            idx < l - 1 ? idx++ : idx = 0; //next index
            console.log( 'index=' + idx );  
            jn = idx < l - 1 ? idx + 1 : 0; //new following image
            imgs.push( d3.select(n[jn]) );
            imgs.shift();
            update( imgs );
        });
    d3.select(".prev")
        .on("mousedown touchstart", function() {
            idx > 0 ? idx-- : idx = l - 1; //prev index
            console.log( 'index=' + idx );
            jp = idx > 0 ? idx - 1 : l - 1; //new preceding image
            imgs.unshift( d3.select(n[jp]) );
            imgs.pop();
            update( imgs );
        });
    d3.select(".close")
        .on("mousedown touchstart", function() {
            d3.select('#luxbox')
                .attr("class", "hide");
            setTimeout( function() {
                d3.selectAll('#slider li').remove();
                console.log('slides removed')
            }, 400 );
        });
}
like image 293
ALx Avatar asked Jan 25 '26 17:01

ALx


1 Answers

After investigating further and finding some great answers, I have solved my problem by using data key matching image selection index.

var imgs = [
    { 
        "url": d3.select(n[jp]).select("img").attr("src"),
        "caption": d3.select(n[jp]).select("img").attr("alt"),
        "key": jp
    },
    { 
        "url": d3.select(n[j]).select("img").attr("src"),
        "caption": d3.select(n[j]).select("img").attr("alt"),
        "key": j
    },
    { 
        "url": d3.select(n[jn]).select("img").attr("src"),
        "caption": d3.select(n[jn]).select("img").attr("alt"),
        "key": jn
    }
];

// ...

.data(data, function(d) { return d.key; }); //join
like image 150
ALx Avatar answered Jan 28 '26 06:01

ALx



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!