3

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

1 Answer 1

3

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.