Je dessine un nuage de points avec d3.js. À l'aide de cette question:
obtenez la taille de l'écran, la page Web actuelle et la fenêtre du navigateur
J'utilise cette réponse:
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth,
y = w.innerHeight|| e.clientHeight|| g.clientHeight;
Je suis donc capable d'adapter mon tracé à la fenêtre de l'utilisateur comme ceci:
var svg = d3.select("body").append("svg")
.attr("width", x)
.attr("height", y)
.append("g");
Maintenant, j'aimerais que quelque chose s'occupe de redimensionner le tracé lorsque l'utilisateur redimensionne la fenêtre.
PS: Je n'utilise pas jQuery dans mon code.
javascript
d3.js
mthpvg
la source
la source
Réponses:
Recherchez `` SVG réactif '', il est assez simple de rendre un SVG réactif et vous n'avez plus à vous soucier des tailles.
Voici comment je l'ai fait:
d3.select("div#chartId") .append("div") // Container class to make it responsive. .classed("svg-container", true) .append("svg") // Responsive SVG needs these 2 attributes and no width and height attr. .attr("preserveAspectRatio", "xMinYMin meet") .attr("viewBox", "0 0 600 400") // Class to make it responsive. .classed("svg-content-responsive", true) // Fill with a rectangle for visualization. .append("rect") .classed("rect", true) .attr("width", 600) .attr("height", 400);
.svg-container { display: inline-block; position: relative; width: 100%; padding-bottom: 100%; /* aspect ratio */ vertical-align: top; overflow: hidden; } .svg-content-responsive { display: inline-block; position: absolute; top: 10px; left: 0; } svg .rect { fill: gold; stroke: steelblue; stroke-width: 5px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div id="chartId"></div>
Remarque: tout ce qui se trouve dans l'image SVG sera mis à l'échelle avec la largeur de la fenêtre. Cela inclut la largeur du trait et les tailles de police (même celles définies avec CSS). Si cela n'est pas souhaité, il existe des solutions alternatives plus impliquées ci-dessous.
Plus d'infos / tutoriels:
http://thenewcode.com/744/Make-SVG-Responsive
http://soqr.fr/testsvg/embed-svg-liquid-layout-responsive-web-design.php
la source
viewBox
attribut doit être défini sur la hauteur et la largeur appropriées de votre tracé SVG:.attr("viewBox","0 0 " + width + " " + height)
oùwidth
etheight
sont définis ailleurs. Autrement dit, à moins que vous ne souhaitiez que votre SVG soit coupé par la zone de visualisation. Vous pouvez également mettre à jour lepadding-bottom
paramètre dans votre css pour qu'il corresponde au rapport hauteur / largeur de votre élément svg. Excellente réponse cependant - très utile et fonctionne un régal. Merci!top: 10px;
? Cela me semble incorrect et fournit un décalage. Mettre à 0px fonctionne très bien.Utilisez window.onresize :
function updateWindow(){ x = w.innerWidth || e.clientWidth || g.clientWidth; y = w.innerHeight|| e.clientHeight|| g.clientHeight; svg.attr("width", x).attr("height", y); } d3.select(window).on('resize.updatesvg', updateWindow);
http://jsfiddle.net/Zb85u/1/
la source
w
,e
,g
comming de nulle part etx
, eny
cours d' initialisation sans mots - clés dans votre réponse.MISE À JOUR utilisez simplement la nouvelle méthode de @cminatti
ancienne réponse à des fins historiques
IMO, il est préférable d'utiliser select () et on () car de cette façon, vous pouvez avoir plusieurs gestionnaires d'événements de redimensionnement ... ne soyez pas trop fou
d3.select(window).on('resize', resize); function resize() { // update width width = parseInt(d3.select('#chart').style('width'), 10); width = width - margin.left - margin.right; // resize the chart x.range([0, width]); d3.select(chart.node().parentNode) .style('height', (y.rangeExtent()[1] + margin.top + margin.bottom) + 'px') .style('width', (width + margin.left + margin.right) + 'px'); chart.selectAll('rect.background') .attr('width', width); chart.selectAll('rect.percent') .attr('width', function(d) { return x(d.percent); }); // update median ticks var median = d3.median(chart.selectAll('.bar').data(), function(d) { return d.percent; }); chart.selectAll('line.median') .attr('x1', x(median)) .attr('x2', x(median)); // update axes chart.select('.x.axis.top').call(xAxis.orient('top')); chart.select('.x.axis.bottom').call(xAxis.orient('bottom')); }
http://eyeseast.github.io/visible-data/2013/08/28/responsive-charts-with-d3/
la source
C'est un peu moche si le code de redimensionnement est presque aussi long que le code de construction du graphique en premier lieu. Donc, au lieu de redimensionner chaque élément du graphique existant, pourquoi ne pas simplement le recharger? Voici comment cela a fonctionné pour moi:
function data_display(data){ e = document.getElementById('data-div'); var w = e.clientWidth; // remove old svg if any -- otherwise resizing adds a second one d3.select('svg').remove(); // create canvas var svg = d3.select('#data-div').append('svg') .attr('height', 100) .attr('width', w); // now add lots of beautiful elements to your graph // ... } data_display(my_data); // call on page load window.addEventListener('resize', function(event){ data_display(my_data); // just call it again... }
La ligne cruciale est
d3.select('svg').remove();
. Sinon, chaque redimensionnement ajoutera un autre élément SVG sous le précédent.la source
Dans les mises en page forcées, le simple fait de définir les attributs 'height' et 'width' ne fonctionnera pas pour recentrer / déplacer le tracé dans le conteneur svg. Cependant, il existe une réponse très simple qui fonctionne pour les dispositions de force trouvées ici . En résumé:
Utilisez les mêmes (tous) événements que vous aimez.
window.on('resize', resize);
Alors en supposant que vous avez des variables svg et force:
var svg = /* D3 Code */; var force = /* D3 Code */; function resize(e){ // get width/height with container selector (body also works) // or use other method of calculating desired values var width = $('#myselector').width(); var height = $('#myselector').height(); // set attrs and 'resume' force svg.attr('width', width); svg.attr('height', height); force.size([width, height]).resume(); }
De cette façon, vous ne restaurez pas entièrement le graphique, nous définissons les attributs et d3 recalcule les choses si nécessaire. Cela fonctionne au moins lorsque vous utilisez un point de gravité. Je ne sais pas si c'est une condition préalable à cette solution. Quelqu'un peut-il confirmer ou nier?
Bravo, g
la source
Pour ceux qui utilisent des graphes dirigés par la force dans D3 v4 / v5, la
size
méthode n'existe plus. Quelque chose comme ce qui suit a fonctionné pour moi (basé sur ce problème github ):simulation .force("center", d3.forceCenter(width / 2, height / 2)) .force("x", d3.forceX(width / 2)) .force("y", d3.forceY(height / 2)) .alpha(0.1).restart();
la source
Si vous voulez la logique BIND pour redimensionner l' événement, de nos jours , vous pouvez commencer à utiliser l' API de navigateur ResizeObserver pour la zone de délimitation d'un SVGElement.
Cela gérera également le cas où le conteneur est redimensionné en raison du changement de taille des éléments à proximité.
Il existe un polyfill pour une prise en charge plus large du navigateur.
Voici comment cela peut fonctionner dans le composant UI:
function redrawGraph(container, { width, height }) { d3 .select(container) .select('svg') .attr('height', height) .attr('width', width) .select('rect') .attr('height', height) .attr('width', width); } // Setup observer in constructor const resizeObserver = new ResizeObserver((entries, observer) => { for (const entry of entries) { // on resize logic specific to this component redrawGraph(entry.target, entry.contentRect); } }) // Observe the container const container = document.querySelector('.graph-container'); resizeObserver.observe(container)
.graph-container { height: 75vh; width: 75vw; } .graph-container svg rect { fill: gold; stroke: steelblue; stroke-width: 3px; }
<script src="https://unpkg.com/[email protected]/dist/ResizeObserver.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <figure class="graph-container"> <svg width="100" height="100"> <rect x="0" y="0" width="100" height="100" /> </svg> </figure>
// unobserve in component destroy method this.resizeObserver.disconnect()
la source