AmCharts ne présente pas de graphique pour les divs initialement cachés

J'utilise AmCharts (qui utilise Raphaël en coulisses) pour rendre certains tableaux comme SVG; Et ont remarqué que si le SVG est rendu dans une division initialement invisible, le navigateur ne rend pas immédiatement l'image lorsque la div devient visible. Si je modifie l'affichage cependant, par exemple en redimensionnant le navigateur ou le zoom Ctrl-mousewheel, l'image SVG est alors rendue comme prévu lorsque la page est redessinée.

La méthode exacte de commutation de visibilité div via via la barre de navigation à onglet de Bootstrap .

J'avoue n'avoir pas beaucoup d'expérience avec SVG: est-ce un problème avec le rendu des navigateurs, ou le balisage SVG d'AmCharts, ou est-ce que je dois appeler explicitement une sorte de méthode de repint lorsque je peux dire que la visibilité d'un SVG a changé?

Voici un jsFiddle qui illustre le problème ; Si vous passez à la section 2 (dans Chrome, Firefox), le graphique n'est pas visible initialement. Le redimensionnement de l'affichage provoque son apparition.

J'ai trouvé la raison pour le comportement initial et la solution de contournement – et tout est amCharts spécifique (rien à voir avec SVG en soi), donc je reformule le titre en conséquence.

Ce qui se passe, c'est que lorsque AmCharts crée le SVG, il doit (ou du moins décider) de définir la largeur et la hauteur en termes absolus. Ils sont basés sur la taille de la offsetWidth cible, obtenue via les propriétés offsetWidth et offsetHeight .

L'onglet inactif affiche l' display: none paramètre de propriété display: none défini et, par conséquent, cette partie du DOM n'est même pas rendue, donc renvoie zéro pour les deux propriétés de taille. Cela amène finalement les AmCharts à créer un diagramme SVG de 0x0 lorsque chart.write est appelé pour la chart.write cachée.

Le redimensionnement corrige les choses car chaque diagramme enregistre un auditeur sur l' onresize fenêtre onresize , qui appelle la méthode handleResize du handleResize . Cela oblige à recalculer la largeur et la hauteur en fonction des nouvelles dimensions (courantes) du div.


Donc en conclusion, je pense qu'il existe deux façons différentes de gérer ceci:

  • Appelez chart.write pour un graphique quand et seulement lorsque son onglet devient visible.
  • Appelez la méthode handleResize chaque graphique lorsque les onglets changent.

(La première option évite le coup initial de rendre un graphique invisible, mais redessine complètement chaque fois que les onglets sont modifiés. Ce dernier prend un coup de tête, mais est probablement plus rapide par la suite. Pour les marques de bonus, la meilleure solution serait Pour rendre chaque graphique exactement une fois entre chaque redimensionnement, la première fois qu'il devient visible, mais cela est beaucoup plus complexe, car cela impliquerait d'interférer avec les auditeurs d'événements par défaut, entre autres.)

Mise à jour : il existe d'autres complications pour rendre un graphique invisible; En particulier, j'ai trouvé des problèmes avec les calculs en hauteur sans tenir compte de l'espace requis par l'axe du domaine et donc d'étirer le graphique hors de sa division. Cela n'a pas été corrigé en appelant handleResize – appelant measureMargins auparavant semblait qu'il devrait fonctionner mais n'a pas. (Il y a probablement une autre méthode que l'on pourrait appeler après cela pour que cela fonctionne comme resetMargins mais à ce stade, il a commencé à se sentir très floconneux …)

En tant que tel, je ne pense pas qu'il soit pratique de rendre un graphique pour la première fois sur une div non visible, alors je suis allé avec une combinaison des balles ci-dessus. J'écoute quand l'onglet d'un graphique devient visible pour la première fois puis appelle chart.write pour l'objet graphique approprié – et chaque fois que les onglets changent, tous les tableaux précédemment rendus sont chargés de gérer le redimensionnement.

* Edité *

Voici un violon mis à jour. La Toile ne sera rendue qu'une fois l'onglet affiché. Je stocke les identifiants chartdiv dans un tableau et vérifie s'il y en a ou non.

* Edité *

La seule solution que j'ai trouvé était de montrer le graphique après l'affichage de l'onglet spécifique.

Comme vous le voyez dans ce 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); }); 

Je suppose que ce n'est pas exactement ce que vous cherchez, mais j'espère que cela vous aidera pour le moment.

J'ai eu le même problème, mais ma solution est alternative à l'affichage: aucune, vous pouvez utiliser cette classe dans le css

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

Ce dissapear de l'écran mais visible pour l'amchart, donc la résolution du graphique ne perd jamais la taille !!!!

Je suis entièrement d'accord avec Andrzej Doyle.

L'émission d'une liste manuelle sur le graphique lorsque vous cliquez sur le div (onglet) sélectionné fonctionne pour moi sur un cs-cart avec des onglets personnalisés (pas jquery).

Les travaux suivants sont définis à l'échelle mondiale.

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

J'ai également rencontré le problème et l'ai corrigé en rendant l'initialiseur une fonction. Travailler .

 $("#button").click(function(){ $("#chartdiv").toggle(); makeChart(); }); function makeChart() { var chart = AmCharts.makeChart("chartdiv", { //all the stuff }); } 

Cela pourrait vous aider à résoudre le problème. J'ai mon Amchart montrant dans différents onglets. Le composant SVG ne leur permet pas de montrer que div en raison d'un problème de redimensionnement.

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

Redimensionnez votre fenêtre lorsque vous créez vos tableaux ..

 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> 

Un autre travail serait

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

Initialement display:inline avec div qui est un conteneur de graphique, il est rendu.

Ensuite, réglez l' display:none utilisant setTimeout() après 1 ms.

J'espère que cela t'aides…

J'ai deux images différentes sur des onglets différents. Un graphique de stock à placer sur #chartdiv et un graphique circulaire à placer sur #chartdivpie. C'est ainsi que j'ai résolu mon problème.

Mon css personnalisé – pour remplacer bootstrap –

 #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; } 

Appel JQuery

 $('#myTab a').click(function (e) { e.preventDefault() $(this).tab('show'); chart.invalidateSize(); chart.write('chartdiv'); }) 
 <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>