2012-04-04 64 views
19

Estoy usando amCharts (que usa Raphaël detrás de las escenas) para representar algunos gráficos como SVG; y hemos notado que si el SVG se representa en un div inicialmente invisible, el navegador no renderiza la imagen inmediatamente cuando el div se vuelve visible. Sin embargo, si modifico la pantalla, p. al redimensionar el navegador o hacer zoom con la rueda Ctrl-mouse, la imagen SVG se procesa como se esperaba cuando se vuelve a dibujar la página.amCharts no muestra el gráfico para los divs ocultos inicialmente

El método exacto de conmutación de visibilidad div es a través de Bootstrap's tabbed navbar.

Admito que no tengo mucha experiencia con SVG: ¿esto es un problema con el renderizado de los navegadores, o el marcado SVG de amCharts, o debo llamar explícitamente algún tipo de método de repintado cuando puedo ver la visibilidad de un SVG ha cambiado?

Aquí hay un jsFiddle which illustrates the problem; si cambia a la Sección 2 (en Chrome, Firefox), el cuadro no está visible inicialmente. Cambiar el tamaño de la pantalla hace que aparezca.

+2

No es un tutorial sobre este tema realizado por amCharts: http://blog.amcharts.com/2012/08/displaying-javascript-charts-in-tabs-or. html – zeroin

+0

Highcharts/Highstock también tiene este problema. – iman

+0

Agregar chart.invalidateSize(); en la pestaña, haga clic. Ref: https://www.amcharts.com/tutorials/displaying-charts-in-tabs-or-other-dynamic-page-elements/ – Raja

Respuesta

22

He encontrado la razón tanto para el comportamiento inicial como para la solución alternativa (y todo es específico de amCharts (nada que ver con SVG per se), así que estoy reformulando el título en consecuencia.

Lo que sucede es que cuando amCharts crea el SVG, necesita (o al menos, decide) definir el ancho y el alto en términos absolutos. Estos se basan en el tamaño del div de destino, obtenido a través de las propiedades offsetWidth y offsetHeight.

La pestaña inactiva tiene el conjunto de propiedades display: none, y como resultado, esta parte del DOM ni siquiera se representa, por lo que devuelve cero para ambas propiedades de tamaño. Esto finalmente lleva a que amCharts cree un gráfico SVG 0x0 cuando se llama al chart.write para el div oculto.

El ajuste de tamaño corrige las cosas porque cada gráfico registra un oyente en el evento de ventana onresize, que llama al método handleResize del gráfico. Esto obliga a volver a calcular el ancho y el alto en función de las nuevas dimensiones (actuales) del div.


Así que en conclusión creo que hay dos maneras alternativas de manejar esta situación:

  • llamada chart.write para un gráfico cuando y sólo cuando la lengüeta se hace visible.
  • Llame al método handleResize de cada gráfico cuando cambien las pestañas.

(La primera opción evita el golpe inicial de hacer un gráfico invisible, pero luego hace redibujo un completo cada vez que se cambian las fichas. Este último recibe un golpe por adelantado, pero es probable que más rápido después de eso. Por marcas de bonificación , la mejor solución sería representar cada gráfico exactamente una vez entre cada cambio de tamaño, la primera vez que se hace visible, pero eso es mucho más complejo ya que implicaría interferir con los detectores de eventos predeterminados, entre otras cosas).

Actualización: hay más complicaciones con la representación de un gráfico invisible; en particular, encontré problemas con los cálculos de altura sin tener en cuenta el espacio requerido por el eje del dominio y, por lo tanto, estirar el gráfico fuera de su div. Esto no se solucionó al llamar al handleResize: llamar al measureMargins de antemano parecía que debería funcionar pero no lo hizo. (Probablemente haya otro método que uno podría llamar después de esto para hacerlo funcionar como resetMargins pero en este punto comenzó a sentirse muy escamoso ...)

Como tal, no creo que sea práctico representar un gráfico para el primera vez en un div no visible, así que fui con alguna combinación de las viñetas de arriba. Escucho cuando la pestaña de un gráfico se vuelve visible por primera vez y luego llamo al chart.write para obtener el objeto de gráfico apropiado, y cada vez que cambian las pestañas, todos los gráficos previamente renderizados reciben el tamaño.

4

escandaloso

Aquí es una actualización fiddle. El lienzo solo se representará una vez que se muestre la pestaña. Guardo los identificadores chartdiv en una matriz y verifico si hay en ella o no.

* * Editado

La única solución que encontré fue mostrar el gráfico se muestra después de la pestaña específica.

Como ve en este jsFiddle.

var tabs = $('.tabbable').tab() 

tabs.on('shown', function(e){ 
    id = $(e.target).attr('href');   
    chartdiv_id = $(id).find('.chartdiv').attr('id');       
    doChart(chartdiv_id, true); 
}); 

Supongo que no es exactamente lo que estás buscando, pero espero que ayude por el momento.

+0

Gracias por su trabajo y la actualización. En la actualidad, todavía hay un error en su última versión (aunque de menor importancia): si cambia entre las pestañas, * entonces * cambia el tamaño del navegador, ambos gráficos se activan para volver a dibujarse y volvemos al punto uno. Esta es la razón por la que mi primera solución propuesta incluía escribir el gráfico * cada * vez que la pestaña se activaba (ejemplo [violín con bifurcación] (http://jsfiddle.net/ErL82/4/)), que supera el efecto de cualquier cambio de tamaño intermedio. –

+1

No hay problema. Me lo perdí. Creo que volver a dibujar las tablas cada vez es probablemente la mejor solución. ¡Gracias por tu voto! Siempre busqué soluciones a mis problemas pero nunca participé y pensé que intentaría ayudar a otros con sus problemas para un cambio. –

+1

He aceptado mi propia respuesta, ya que explica con qué me he ido, pero gracias de nuevo por su ayuda. En particular, su idea de identificar la pestaña específica que se activó fue importante para evitar que se estiren los márgenes del área de trazado. –

3

he tenido el mismo problema, pero mi solución que es alternativa a la pantalla: ninguno, puede utilizar esta clase en el css

.hidden { 
    position: absolute !important; 
    top: -9999px !important; 
    left: -9999px !important; 
} 

este desaparecer de la pantalla, pero visible para el amchart, por lo que la resolución de la tabla nunca pierde el tamaño !!!!

+0

¡No hay manera más simple que eso, gracias! – ranell

0

Otro trabajo alrededor sería

drawTransactionTypeChart(); 
setTimeout(function(){hidePieCharts();},1); 

establece inicialmente display:inline a DIV que es recipiente de la carta, que se rindió.

Luego configure display:none usando setTimeout() después de 1ms.

Espero que esto ayude ...

1

estoy completamente de acuerdo con Andrzej Doyle.

Emitir handleresize en el gráfico al hacer clic en la div (pestaña) seleccionada funciona para mí en c-cart con pestañas personalizadas (no en las de Java).

Lo siguiente funciona mientras el carrito de compras está definido globalmente.

function refreshchart(){ 
     chart.handleResize(); 
    }; 
0

que tienen dos amCharts en diferentes pestañas. Un gráfico de valores que se colocará en #chartdiv y un gráfico circular que se colocará en #chartdivpie. Así es como resolví mi problema.

Mi CSS personalizado - sobrescribir arranque -

#chartdivpie { width: 1138px; height: 500px; } 
.tab-content .tab-pane { 
    position: absolute; 
    top: -9999px; 
    left: -9999px; 
    display: inline; 
} 
.tab-content .tab-pane.active { 
    position: inherit !important; 
} 

jQuery llamada

$('#myTab a').click(function (e) { 
     e.preventDefault() 
     $(this).tab('show'); 
     chart.invalidateSize(); 
     chart.write('chartdiv'); 
    }) 
1

Esto podría ayudarle a resolver la cuestión. Tengo mi amchart mostrando en una pestaña diferente. El componente SVG no les permite mostrar ese div debido al problema de cambio de tamaño.

$(window).resize(function() { 
    setTimeout(function() { 
     chart.write("chartdiv1"); 
    }, 300); 
}); 

cambio de tamaño de nuevo la ventana mientras crea sus tablas ..

1

también se encontró con el problema y lo arreglaron al hacer que el inicializador de una función. Working fiddle.

$("#button").click(function(){ 
    $("#chartdiv").toggle(); 
    makeChart(); 
}); 

function makeChart() { 
    var chart = AmCharts.makeChart("chartdiv", { 
     //all the stuff 
    }); 
} 
1
var chart = null; 
AmCharts.ready(function() { 
    chart = AmCharts.makeChart('chart', .....); 
}); 
$(document).ready(function(){ 
    $("#view_chart").click(function(){ 
     chart.validateSize(); 
    }); 
}); 


<button type="button" id="view_chart">View Chart</button> 
<div style="display:none;" id="chart"></div> 
0
<a href="#" class="show_charts">Show me charts</a> 
<div class="charts_div" style="display:hidden;"> 
some charts here 
</div> 
<script> 
    $(document).on('click', '.show_charts', function(){ 
     $('.charts_div').toggle(); 
     //just redraw all charts available on the page 
     for(var i = 0; i < AmCharts.charts.length; i++) { 
      AmCharts.charts[i].validateData(); 
     } 
    }); 
</script> 
Cuestiones relacionadas