Migrate SVG when resizing

I am trying to redraw the SVG diagram when I resize the window in d3, but without using the viewBox and preserveAspectRatio parameters (I did not like how they processed the text).

I am also trying to stick to the d3-binding design through the Bostock sentence when adding one element (not based on backup data).

I have something that boils down to this ( jsFiddle ). However, the width / height of an SVG element is never updated.

HTML

 <div class="chart-container"> <button class="user-option">Some User Options</button> <div class="svg-container"></div> </div> 

Javascript

 $(window).on("resize", function () { draw(); }); function draw() { var container = d3.select('.chart-container'); var drawWidth = Math.round(0.80 * container.node().clientWidth); var drawHeight = Math.round(drawWidth * (3 / 4)); // Fixing a 4/3 aspect ratio /* * Use an inner g element as the SVG canvas in order to set and forget margins. * See http://bl.ocks.org/mbostock/3019563 */ var margin = { top: 10, right: 30, bottom: 50, left: 40 }; var width = drawWidth - margin.left - margin.right; var height = drawHeight - margin.top - margin.bottom; var svg = container.select(".svg-container").selectAll('svg') .data([0]) // Single data element to create SVG if it doesn't exist .enter().append("svg") .attr("width", drawWidth) .attr("height", drawHeight) .append("g") .attr("class", "canvas") // jsFiddle doesn't translate correctly, maybe because of frames??? .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); console.debug(svg.node()); // null on resize??? // Add some random SVG element svg.selectAll('rect') .data([0]) // Single data element to create SVG if it doesn't exist .enter().append('rect') .attr({ x: 0, y: 0, width: drawWidth - margin.right - margin.left, height: drawHeight - margin.bottom - margin.top }); } 
+5
source share
4 answers

Thank you, I was able to get the right solution from all your answers! However, no answer was able to update the SVG when resizing AND save the svg variable as the g element (adhere to the margin agreement ). I finished doing

 // Create SVG element (if it doesn't exist) var svg = container.select(".svg-container").selectAll('svg').data([null]); svg.enter().append("svg"); svg.attr({width: drawWidth, height: drawHeight}); // apply to enter + update selections // Create g element (if it doesn't exist) and remap the svg variable svg = svg.selectAll(".canvas").data([null]); svg.enter().append("g") // apply to enter selection only .attr("class", "canvas") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
+1
source

The root problem here is that your svg variable is not assigned the choice of the <svg> element, which is assigned the final result of calls with chain calls, the first round of which is the <g> element, and after that is empty, because there is no 'enter' choice .

So the first thing to do is change to

 var svg = container.select(".svg-container").selectAll('svg').data([0]); // now you have a reference to the svg selection 

At the first run, the update selection will be empty, and the input selection will contain one element. Then you bind this to the new <svg> element:

 svg.enter() .append("svg") .append("g") // note that from this point you're setting attributes on the <g>, not the <svg> .attr("class", "canvas") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

This add operation adds an item to the update selection stored in svg .

When resizing, the input selection will be empty, but the update selection in svg will already contain the existing <svg> element. One way or another, at this point you can set attributes in svg selection - it will work for both cases.

 svg.attr("width", drawWidth) .attr("height", drawHeight); 

Updated fiddle http://jsfiddle.net/3dgn5pz8/5/

+3
source

@Pablo Navarro the answer is closed, the only problem is that the svg on the redraw will not be your svg element, but an array, use the same method of separating the two executions, but select your svg again to change the width and height

 var svg = container.select(".svg-container").selectAll('svg') .data([0]) // Single data element to create SVG if it doesn't exist .enter().append("svg") .append("g") .attr("class", "canvas") // jsFiddle doesn't translate correctly, maybe because of frames??? .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

then

 container.select(".svg-container").select('svg').attr("width", drawWidth).attr("height", drawHeight) 

http://jsfiddle.net/LLvuq0Lm/9/

+1
source

You only set the width and height of the svg element as you type, if the element already exists, it is not updated. Try updating the item after creating the item (and child group):

  var svg = container.select(".svg-container").selectAll('svg') .data([0]) // Single data element to create SVG if it doesn't exist .enter().append("svg") .append("g") .attr("class", "canvas") // jsFiddle doesn't translate correctly, maybe because of frames??? .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg.attr("width", drawWidth).attr("height", drawHeight) 

Hi,

0
source

Source: https://habr.com/ru/post/1201350/


All Articles