2012-04-04 6 views
19

Używam amCharts (który używa Raphaël za kulisami) do renderowania niektórych wykresów jako SVG; i zauważyłem, że jeśli SVG jest renderowany w początkowo niewidocznym div, przeglądarka nie renderuje natychmiast obrazu, gdy div staje się widoczny. Jeśli jednak zmienię wyświetlanie, np. poprzez zmianę rozmiaru przeglądarki lub powiększenie za pomocą Ctrl-kółka myszy, obraz SVG jest renderowany zgodnie z oczekiwaniami, gdy strona jest przerysowana.amCharts nie wyświetla wykresu dla początkowo ukrytych elementów div

Dokładna metoda przełączania widoczności div odbywa się przez Bootstrap's tabbed navbar.

Przyznaję, że nie mam dużego doświadczenia z SVG - czy jest to problem związany z renderowaniem przeglądarek lub znacznikiem SVG amCharts, czy też muszę wyraźnie wywołać metodę odświeżania, gdy mogę powiedzieć, że jest widoczna SVG się zmieniło?

Oto jsFiddle which illustrates the problem; jeśli przejdziesz do sekcji 2 (w przeglądarce Chrome, Firefox), wykres nie będzie początkowo widoczny. Zmiana rozmiaru wyświetlacza powoduje jego pojawienie się.

+2

Jest poradnik na ten temat wykonanej przez amCharts: http://blog.amcharts.com/2012/08/displaying-javascript-charts-in-tabs-or. html – zeroin

+0

Highcharts/Highstock również ma ten problem. – iman

+0

Dodaj chart.invalidateSize(); w karcie kliknij. Ref: https://www.amcharts.com/tutorials/displaying-charts-in-tabs-or-other-dynamic-page-elements/ – Raja

Odpowiedz

22

Znalazłem przyczynę zarówno wstępnego zachowania, jak i obejścia - i to wszystko jest specyficzne dla amCharts (nie ma nic wspólnego z SVG per se), więc odpowiednio zmieniam tytuł.

Co się dzieje, gdy amCharts tworzy SVG, musi (lub przynajmniej decyduje się) zdefiniować szerokość i wysokość w wartościach bezwzględnych. Są one oparte na rozmiarze docelowego elementu div uzyskanego za pomocą właściwości offsetWidth i offsetHeight.

Nieaktywna karta ma ustawioną właściwość display: none iw rezultacie ta część DOM nie jest nawet renderowana, więc zwraca zero dla obu właściwości rozmiaru. To ostatecznie prowadzi do amCharts tworzenia wykresu SVG 0x0, gdy chart.write jest wywoływana dla ukrytego div.

Zmiana rozmiaru rozwiązuje problem, ponieważ każdy wykres rejestruje odbiorcę w zdarzeniu okna onresize, które wywołuje metodę z tabeli handleResize. Wymusza to ponowne obliczenie szerokości i wysokości w oparciu o nowe (bieżące) wymiary elementu div.


Tak na zakończenie Myślę, że istnieją dwa sposoby, aby sobie z tym poradzić:

  • połączeń chart.write na wykresie wtedy i tylko wtedy, gdy jego zakładka staje się widoczny.
  • Zadzwoń do każdego z nich, używając metody handleResize, gdy zmieniają się karty.

(Pierwsza opcja pozwala uniknąć początkowego trafienia renderowania niewidocznej mapy, ale następnie wykonuje pełne przerysowanie za każdym razem, gdy zmienione są zakładki, która wykonuje uderzenie z góry, ale prawdopodobnie później szybciej. , najlepszym rozwiązaniem byłoby renderowanie każdego wykresu dokładnie jeden raz pomiędzy każdą zmianą rozmiarów, przy pierwszym wyświetleniu, ale jest to o wiele bardziej złożone, ponieważ wymagałoby to między innymi ingerencji w domyślne detektory zdarzeń.)

Aktualizacja: Istnieją dalsze komplikacje z renderowaniem niewidocznego wykresu; w szczególności, znalazłem problemy z obliczeniami wysokości nie biorąc pod uwagę przestrzeni wymaganej przez oś domeny, a więc wyciągając wykres z jego div. Nie zostało to naprawione przez wywołanie handleResize - wywołanie wcześniej wyglądało tak, jak powinno, ale nie działa. (Prawdopodobnie istnieje inna metoda, którą można wywołać po tym, aby zadziałać tak, jak resetMargins, ale w tym momencie zaczęło się wydawać bardzo niestabilne ...)

W związku z tym nie wydaje mi się praktyczne, aby wyrenderować wykres dla pierwszy raz na niewidocznym div, więc poszedłem z kombinacją powyższych kul. Słucham, kiedy zakładka wykresu staje się widoczna po raz pierwszy, a następnie wywołuje chart.write dla odpowiedniego obiektu wykresu - a gdy zmieniają się tabulatory, wszystkie uprzednio renderowane wykresy są informowane, aby obsłużyć zmianę rozmiaru.

4

* Zmieniano *

Oto aktualizowane fiddle. Obraz zostanie wyświetlony dopiero po wyświetleniu karty. Przechowuję identyfikatory na tablicy wyników w tablicy i sprawdzam, czy są w niej obecne, czy też nie.

* Pod *

Jedynym rozwiązaniem I stwierdzono, aby pokazać na wykresie, po języczek specyficzne pokazane.

Jak widać w tym 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); 
}); 

Zgaduję, że nie jest to dokładnie to, czego szukasz, ale mam nadzieję, że pomaga na razie.

+0

Dzięki za twoją pracę i aktualizację. W tej chwili nadal występuje błąd w najnowszej wersji (aczkolwiek niewielki) - jeśli przełączysz się między kartami, * wtedy * zmienisz rozmiar przeglądarki, obie wykresy zostaną uruchomione, aby przerysować się i wrócimy do pierwszego. Dlatego moje pierwsze proponowane rozwiązanie zawierało zapisywanie wykresu * co * raz, kiedy zakładka stała się aktywna (przykład [rozwidlone skrzypce] (http://jsfiddle.net/ErL82/4/)), co eliminuje efekt dowolnych przejściowych zmian rozmiaru. –

+1

Bez problemu. Tęsknie za tym. Uważam, że ponowne rysowanie wykresów za każdym razem jest prawdopodobnie najlepszym rozwiązaniem. Dziękuję za przegraną! Zawsze szukałem rozwiązań dla moich problemów, ale nigdy nie brałem udziału i sądziłem, że próbuję pomóc innym w ich problemach. –

+1

Przyjąłem własną odpowiedź, ponieważ wyjaśnia ona, z czym faktycznie się spotkałem, ale jeszcze raz dziękuję za pomoc. W szczególności twoja idea identyfikacji konkretnej karty, która stała się aktywna, była ważna, aby zapobiec rozciągnięciu marginesów obszaru wydruku. –

3

miałem ten sam problem, ale moje rozwiązanie jest alternatywą dla display: none, można użyć tej klasy w css

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

to dissapear ekranu, ale widoczne dla amchart, więc rozdzielczość wykres nigdy nie traci wielkości !!!!

+0

Prostszy sposób niż to, dzięki! – ranell

0

Innym obejść byłoby

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

Stężałej display:inline do dział, który jest pojemnik wykres, pobiera renderowane.

Następnie ustaw display:none za pomocą setTimeout() po 1ms.

Nadzieja to pomaga ...

1

Całkowicie zgadzam się z Andrzejem Doyle.

Wydanie handleresize na wykresie po kliknięciu wybranego div (zakładki) działa dla mnie na cs-cart z niestandardowymi zakładkami (nie jquery ones).

Poniższe działa, gdy wózek jest zdefiniowany globalnie.

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

mam dwa amcharts na różnych kartach. Wykres giełdowy, które należy umieścić na # chartart i wykres kołowy, który należy umieścić na #chartdivpie. Oto jak rozwiązałem mój problem.

Moje niestandardowe css - nadpisać 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; 
} 

JQuery wezwanie

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

To może pomóc rozwiązać problem. Mam mój amchart pokazujący na innej patelni z zakładkami. Komponent SVG nie pozwala im pokazać tego elementu div z powodu zmiany rozmiaru problemu.

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

Resize ponownie Twoje okno podczas tworzenia wykresów ..

1

ja również wpadł problemu i naprawić go poprzez inicjatora funkcję. 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> 
Powiązane problemy