D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
headwinds
Full window
Github gist
cards update pattern
Built with
blockbuilder.org
<!DOCTYPE html> <meta charset="utf-8"> <div style="color: #999; font-size: 40px; font-family: Helvetica">Click on a card</div> <svg width="960" height="500"></svg> <script src="https://d3js.org/d3.v5.min.js"></script> <script> const createData = () => { const coin_flip = Math.random() * 100; const new_card_data_a = [ {id: 0, selected: Math.random() * 10}, {id: 1, selected: Math.random() * 10}, {id: 2, selected: Math.random() * 10}, {id: 3, selected: Math.random() * 10}, {id: 4, selected: Math.random() * 10}, {id: 5, selected: Math.random() * 10}, {id: 6, selected: Math.random() * 10}, ] const new_card_data_b = [ {id: 0, selected: Math.random() * 10 }, {id: 1, selected: Math.random() * 10}, {id: 2, selected: Math.random() * 10}, {id: 3, selected: Math.random() * 10}] const new_card_data = (coin_flip > 50 ) ? new_card_data_a : new_card_data_b; return new_card_data; } const card_data = createData(); let cards_clicked = []; const updateData = (lastData) => { const updated_data = lastData.map( card => { // is the card in the cards_clicked array? const found = cards_clicked.find(card_clicked => card_clicked.id === card.id) if (found !== undefined ) return {...card, clicked: true}; else return {...card, clicked: false}; }) return updated_data; } var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), g = svg.append("g").attr("transform", "translate(32," + (height / 8) + ")"); const getNewColor = (d) => { let newColor; if (d.clicked) return "cyan"; if (Number(d.selected) > 5 ) newColor = "pink"; else newColor = "lightgray"; return newColor; } function handleCardClick(card){ console.log("click card: ",card) //console.log("click cards_clicked: ",cards_clicked) //new_card_data = updateCardData(card_data); const found = cards_clicked.find(card_clicked => card_clicked.id === card.id) const foundIndex = cards_clicked.find(card_clicked => card_clicked.id === card.id) let new_cards_clicked; if (found !== undefined ) { new_cards_clicked = cards_clicked.filter(card_clicked => card_clicked.id !== card.id) cards_clicked = new_cards_clicked; console.log(cards_clicked.length) } else cards_clicked.push(card) cards_clicked.sort((a, b) => parseFloat(a.id) - parseFloat(b.id)); const updated_card_data = updateData(card_data) update(updated_card_data); } function update(newData) { // DATA JOIN // Join new data with old elements, if any. var card = g.selectAll("g") .data(newData); function getTrans(d,i){ const y = (d.clicked) ? -50 : 30; return "translate (" + i * 64 + "," + y + ")" } // UPDATE // Update old elements as needed. //card //.attr("transform", getTrans); // ENTER // Create new elements as needed. // // ENTER + UPDATE // After merging the entered elements with the update selection, // apply operations to both. // need to better under merge // https://github.com/d3/d3-selection#selection_data const cardContainer = card.enter() .append("g") .attr("transform", getTrans); cardContainer .on("click", d => handleCardClick(d) ); cardContainer .append("rect") .attr("class", "card") .attr("width", 60) .attr("height", 100) .attr("fill", d => { return "white" }) .style("stroke-width", "1") // after - entering and updating items! .merge(card) .transition() .duration(1000) .select("rect") .style("stroke", "gray") .style("stroke-width", "2") //.attr("y", String(Math.random() * 10)+"em") .attr("fill", d => { return getNewColor(d) }); cardContainer .append("text") .text(d => d.id) .style("pointer-events","none") .style("fill","#666") .style("opacity",0) .style("font-size",40) .style("font-family","Helvetica Neue") .attr("x", 18) .attr("y", 66) .merge(card) .transition() .delay(500) .duration(1000) .select("text") .style("opacity",1); cardContainer .merge(card) .transition() .attr("transform", getTrans) // EXIT // Remove old elements as needed. card.exit() .transition() .duration(1000) .select("rect") .style("opacity",0) .remove(); } // The initial display. update(card_data); // Grab a random sample of letters from the alphabet, in alphabetical order. const begin = () => { d3.interval(function() { const updated_card_data = updateData(card_data) update(updated_card_data); }, 250); } begin(); </script>
https://d3js.org/d3.v5.min.js