Suponha que eu tenho um script de histograma que cria um gráfico de 960 500 svg. Como faço para que isso seja responsivo, o redimensionamento das larguras e alturas do gráfico é dinâmico?
<script>
var n = 10000, // number of trials
m = 10, // number of random variables
data = [];
// Generate an Irwin-Hall distribution.
for (var i = 0; i < n; i++) {
for (var s = 0, j = 0; j < m; j++) {
s += Math.random();
}
data.push(s);
}
var histogram = d3.layout.histogram()
(data);
var width = 960,
height = 500;
var x = d3.scale.ordinal()
.domain(histogram.map(function(d) { return d.x; }))
.rangeRoundBands([0, width]);
var y = d3.scale.linear()
.domain([0, d3.max(histogram.map(function(d) { return d.y; }))])
.range([0, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
svg.selectAll("rect")
.data(histogram)
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return height - y(d.y); })
.attr("height", function(d) { return y(d.y); });
svg.append("line")
.attr("x1", 0)
.attr("x2", width)
.attr("y1", height)
.attr("y2", height);
</script>
O exemplo completo do histograma gist é: https://gist.github.com/993912
javascript
responsive-design
d3.js
Matt Alcock
fonte
fonte
Respostas:
Há outra maneira de fazer isso que não requer redesenho do gráfico e envolve a modificação dos atributos viewBox e preserveAspectRatio no
<svg>
elemento:Atualização 24/11/15 : os navegadores mais modernos podem inferir a proporção dos elementos SVG a partir de
viewBox
, portanto, talvez você não precise manter o tamanho do gráfico atualizado. Se você precisar dar suporte a navegadores antigos, poderá redimensionar seu elemento quando a janela for redimensionada da seguinte forma:E o conteúdo do svg será redimensionado automaticamente. Você pode ver um exemplo prático disso (com algumas modificações) aqui : basta redimensionar a janela ou o painel inferior direito para ver como ele reage.
fonte
onload
chamada de função. Se a largura e a altura do svg estiverem definidas no html real e você usar a técnica acima, a imagem não será escalável.Procure por 'SVG responsivo'. É muito simples fazer um SVG responsivo e você não precisa mais se preocupar com tamanhos.
Aqui está como eu fiz isso:
O código CSS:
Mais informações / tutoriais:
http://demosthenes.info/blog/744/Make-SVG-Responsive
http://soqr.fr/testsvg/embed-svg-liquid-layout-responsive-web-design.php
fonte
Eu codifiquei uma pequena essência para resolver isso.
O padrão geral da solução é este:
Também adicionei o script d3.js. minificado para velocidade. A essência está aqui: https://gist.github.com/2414111
código de referência de referência jquery:
Código de debounce:
Aproveitar!
fonte
Sem usar o ViewBox
Aqui está um exemplo de uma solução que não depende do uso de um
viewBox
:A chave está na atualização do intervalo das escalas que são usadas para colocar dados.
Primeiro, calcule sua proporção original:
Em cada redimensionamento, atualize o
range
dex
ey
:Observe que a altura é baseada na largura e na proporção, para que suas proporções originais sejam mantidas.
Por fim, "redesenhe" o gráfico - atualize qualquer atributo que dependa de uma das escalas
x
ouy
:Observe que, ao redimensionar o tamanho,
rects
você pode usar o limite superiorrange
dey
, em vez de usar explicitamente a altura:Mostrar snippet de código
fonte
Se você estiver usando o d3.js até o c3.js, a solução para o problema de responsividade é bastante direta:
onde o HTML gerado se parece:
fonte
A resposta de Shawn Allen foi ótima. Mas você pode não querer fazer isso sempre. Se você o hospedar no vida.io , você será responsivo automaticamente pela sua visualização svg.
Você pode obter um iframe responsivo com este código de incorporação simples:
http://jsfiddle.net/dnprock/npxp3v9d/1/
Divulgação: eu construir esse recurso a vida.io .
fonte
No caso de você estar usando um wrapper d3 como o plottable.js , saiba que a solução mais fácil pode ser adicionar um ouvinte de evento e, em seguida, chamar uma função de redesenho (
redraw
em plottable.js). No caso do plottable.js, isso funcionará de maneira excelente (essa abordagem está mal documentada):fonte
Caso as pessoas ainda estejam visitando esta pergunta - eis o que funcionou para mim:
Coloque o iframe em uma div e use css para adicionar um preenchimento de, digamos, 40% a essa div (a porcentagem dependendo da proporção que você deseja). Em seguida, defina a largura e a altura do próprio iframe como 100%.
No documento html que contém o gráfico a ser carregado no iframe, defina a largura como a largura da div à qual o svg é anexado (ou à largura do corpo) e defina a proporção da largura para a largura *.
Escreva uma função que recarrega o conteúdo do iframe no redimensionamento da janela, para adaptar o tamanho do gráfico quando as pessoas rodam o telefone.
Exemplo aqui no meu site: http://dirkmjk.nl/en/2016/05/embedding-d3js-charts-responsive-website
ATUALIZAÇÃO 30 de dezembro de 2016
A abordagem que descrevi acima tem algumas desvantagens, principalmente porque ela não leva em consideração a altura de nenhum título e legenda que não fazem parte do svg criado pelo D3. Desde então, me deparei com o que considero uma abordagem melhor:
Exemplo aqui no meu site: http://dirkmjk.nl/en/2016/12/embedding-d3js-charts-responsive-website-better-solution
fonte
Um dos princípios básicos da junção de dados D3 é que ela é idempotente. Em outras palavras, se você avaliar repetidamente uma junção de dados com os mesmos dados, a saída renderizada será a mesma. Portanto, desde que você renderize seu gráfico corretamente, tomando cuidado com as seleções de entrada, atualização e saída - tudo o que você precisa fazer quando o tamanho muda, é renderizar novamente o gráfico na sua totalidade.
Há algumas outras coisas que você deve fazer, uma delas é devolver o manipulador de redimensionamento da janela para acelerá-la. Além disso, em vez de codificar larguras / alturas, isso deve ser alcançado medindo o elemento que o contém.
Como alternativa, aqui está seu gráfico renderizado usando d3fc , que é um conjunto de componentes D3 que manipulam corretamente junções de dados. Ele também possui um gráfico cartesiano que o mede contendo o elemento, facilitando a criação de gráficos 'responsivos':
Você pode vê-lo em ação neste codepen:
https://codepen.io/ColinEberhardt/pen/dOBvOy
onde você pode redimensionar a janela e verificar se o gráfico foi corretamente renderizado novamente.
Observe que, como uma divulgação completa, sou um dos mantenedores do d3fc.
fonte
Eu evitaria o redimensionamento / tick de soluções como a praga, uma vez que são ineficientes e podem causar problemas no seu aplicativo (por exemplo, uma dica de ferramenta recalcula a posição em que ela deve aparecer no redimensionamento da janela; em seguida, um momento depois, o gráfico também é redimensionado e a página é redimensionada. layouts e agora sua dica está incorreta novamente).
Você pode simular esse comportamento em alguns navegadores antigos que também não o suportam adequadamente, como o IE11, usando um
<canvas>
elemento que mantém seu aspecto.Dado 960x540, que é um aspecto de 16: 9:
fonte
Muitas respostas complexas aqui.
Basicamente, tudo que você precisa fazer é abandonar os atributos
width
eheight
em favor doviewBox
atributo:Se você tiver margens, basta adicioná-las à largura / altura e depois anexá-
g
las posteriormente e transformá-las como faria normalmente.fonte
Você também pode usar o bootstrap 3 para adaptar o tamanho de uma visualização. Por exemplo, podemos configurar o código HTML como:
Configurei uma altura fixa devido às minhas necessidades, mas você também pode deixar o tamanho automático. O "col-sm-6 col-md-4" torna o div responsivo a diferentes dispositivos. Você pode saber mais em http://getbootstrap.com/css/#grid-example-basic
Podemos acessar o gráfico com a ajuda da id month-view .
Não entrarei em muitos detalhes sobre o código d3, apenas inserirei a parte necessária para adaptar a diferentes tamanhos de tela.
A largura é definida obtendo-se a largura da div com o id month-view.
A altura no meu caso não deve incluir toda a área. Também tenho algum texto acima da barra, por isso preciso calcular essa área também. Por isso identifiquei a área do texto com o id responsivetext. Para calcular a altura permitida da barra, subtraí a altura do texto da altura da div.
Isso permite que você tenha uma barra que adotará todos os diferentes tamanhos de tela / div. Pode não ser a melhor maneira de fazê-lo, mas certamente funciona para as necessidades do meu projeto.
fonte