简体   繁体   中英

How to create variable number of image or circle elements in an SVG element using a loop in D3 js(v3)

I'm trying to make a pictogram using d3. So, I have a scaled value with a range from 1 to 10, and I want to create images or circles to represent the numbers, that is, 7 circles or images for number 7, 5 for number 5 etc. The image or circle tag should be drawn on a 'mousein' event. 'mouseout' event shouldn't remove the images. But every mousein event should redraw correct number of circles. Can someone demonstrate a simple example with the right approach?

Things I've tried: I'm able to append n image tags to the svg element but I'm only able to remove the last element since the variable gets the value of last circle drawn.

for(i=1;i<limit;i++){         // 1<=limit<=10 --> Scaled value on each mousein event
    var img = svg.append("image")
      .attr("x", i*width*1/8)
      .attr("y", height*1/10)
      .style("opacity", 1)
      .attr("width", 50)
      .attr("height", 50)
      .attr("xlink:href", "image.png")
      .attr("class", "image");    
    }

When I put all the elements in a group, the image is not being displayed but the elements are present in DOM and also shows the correct path to the image.

The whole power of D3.js lies in its ability to bind data to display elements so you don't have to write loops to manually add items to the DOM.

This example demonstrates adding circles to the SVG element using the selectAll() , data() , enter() and remove() functions which are described in Mike Bostock's article Thinking in Joins .

 const width = 500; const height = 500; let svg = d3.select('svg') // create the rectangles to hover over let rectangleHolders = svg.select('.rectangle-holder').selectAll('rect').data([1, 2, 3, 4, 5]).enter() // to add a rectangle with text, we need to add a group to hold both elements.append('g') // translate group to correct position.attr('transform', (d, i) => `translate(${i*40})`) // add rectangle to each group rectangleHolders.append('rect').attr('height', 18).attr('width', 18) // add event handler to rectangle to draw circles.on('mouseover', draw) // add text to each group rectangleHolders.append('text').attr('dy','15').attr('dx','10').attr('text-anchor','middle').text(d => d) // function to draw circles function draw(number) { console.log('draw', number) // create some dummy data in this case an // array of length 'count' full of nulls const data = Array(number) // select circle elements and bind data let circles = svg.select('.circle-holder').selectAll('circle').data(data) // enter, append and set attributes circles.enter().append('circle').attr('cx', (d, i) => i * 20 + 10).attr('cy', 10).attr('r', 8).attr('value', d => d) // add a tranisition to the opacity so the circles fade in.attr('opacity', 0).transition().attr('opacity', 1) // exit and remove unused elements (with transition) circles.exit().transition().attr('opacity', 0).remove() }
 rect { fill: none; stroke: black; } body { font-family:sans-serif; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <svg height="40" width="200"> <g class="rectangle-holder"></g> <g class="circle-holder" transform="translate(0,20)"></g> </svg>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM