私はd3.jsで散布図を描いています。この質問の助けを借りて:
画面のサイズ、現在のWebページ、ブラウザウィンドウを取得する
私はこの答えを使っています:
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;
だから私はこのように私のプロットをユーザーのウィンドウに合わせることができます:
var svg = d3.select("body").append("svg")
.attr("width", x)
.attr("height", y)
.append("g");
ユーザーがウィンドウのサイズを変更したときに、何かがプロットのサイズを変更するようにしたいのです。
シモンズ:私は自分のコードでjQueryを使っていません。
SVGをレスポンシブにするのはとても簡単で、サイズを気にする必要はもうありません。
これが私のやり方です。
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>
注:SVG画像内のすべてのものはウィンドウ幅に合わせて拡大縮小されます。これにはストローク幅とフォントサイズが含まれます(CSSで設定されている場合でも)。これが望ましくない場合は、以下のより複雑な代替ソリューションがあります。
詳細情報/チュートリアル:
http://thenewcode.com/744/Make-SVG-Responsive
http://soqr.fr/testsvg/embed-svg-liquid-layout-responsive-web-design.php
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);
UPDATE@cminattiの新しい方法を使う
歴史的な目的のための古い答え
IMOそれはあなたが複数のサイズ変更イベントハンドラを持つことができるのでそのようにselect()とon()を使用することをお勧めします。
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/
サイズ変更コードが、最初にグラフを作成するためのコードとほぼ同じ長さである場合、それはちょっと見苦しいです。それでは、既存のチャートのすべての要素のサイズを変更する代わりに、単にそれをリロードしないのはなぜでしょうか。これが私にとってどのように機能したかです。
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...
}
重要な行はd3.select('svg').remove();
です。そうでなければ、それぞれのサイズ変更は前のものの下に別のSVG要素を追加するでしょう。
強制レイアウトでは、単に 'height'および 'width'属性を設定しても、プロットをsvgコンテナに再センタリングまたは移動することはできません。しかし、Force Layoutsに有効な非常に単純な答えがあります こちら 。要約すれば:
あなたが好きな同じ(任意の)イベントを使用してください。
window.on('resize', resize);
それでは、svgと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();
}
このようにして、グラフ全体を再描画するのではなく、属性を設定し、d3で必要に応じて再計算します。これは少なくとも重心を使っているときにうまくいきます。それがこのソリューションの前提条件かどうかはわかりません。誰かが確認または拒否できますか?
乾杯、g
イベントをリサイズするためにカスタムロジックをバインドしたい場合、 今日 あなたはSVGElementのバウンディングボックスに ResizeObserverブラウザAPI を使い始めるかもしれません。
これは、近くの要素のサイズが変更されたためにコンテナーのサイズが変更された場合も処理されます。
より広いブラウザサポートのために polyfill があります。
これが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()
D3 v4/v5で強制有向グラフを使っている人には、size
メソッドはもう存在しません。次のようなものが私のために働きました( この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();
クライアントの幅にはwindow.innerWidthを、クライアントの高さにはwindow.innerHeightを使用します。