Zmiana rozmiaru płótna Chart.js.

86

W ( Błąd kanwy HTML5 Android WebView ) opublikowałem pytanie dotyczące kreślenia wykresów za pomocą biblioteki Graph.js. Problem, który mam teraz, polega na tym, że jeśli wywołuję funkcję w celu wielokrotnego wykreślania wykresu, płótno zmienia rozmiar za każdym razem. Za każdym razem, gdy wykres jest przerysowywany do tego samego obszaru roboczego, jego rozmiar również się zmienia. Próbowałem też ustawić rozmiar płótna, ale bezskutecznie.

Jaki może być tego powód? Dlaczego płótno zmienia rozmiar za każdym razem?

Jaka
źródło
Teraz ich strona jest poświęcona tej na oficjalnej stronie Chart.js, tutaj: chartjs.org/docs/latest/general/responsive.html Testowałem rozwiązanie i działa dobrze.
Amine 27

Odpowiedzi:

175

Miałem z tym sporo problemów, bo po tym wszystkim moja grafika liniowa wyglądała fatalnie po najechaniu myszą i znalazłem prostszy sposób na zrobienie tego, mam nadzieję, że to pomoże :)

Użyj tych opcji Chart.js:

// Boolean - whether or not the chart should be responsive and resize when the browser does.

responsive: true,

// Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container

maintainAspectRatio: false,
NoFlag
źródło
Dzięki @NoFlag za odpowiedź. Dla mnie atrybuty wysokości i szerokości nie były stosowane do płótna, na wypadek, gdyby ktoś znalazł się tutaj, szukając rozwiązania dla próby zmiany rozmiaru płótna, spróbuj ustawić responsywność na true. * Chart.defaults.global.responsive = false *
sghosh968
13
Nie zapominaj, że aby ta metoda działała poprawnie, musisz umieścić płótno w a <div>i ustawić wysokość i / lub szerokość na wspomnianym <div>zamiast płótnie.
totymedli
2
Te flagi są teraz domyślnie ustawione na true, więc nie musisz ich dotykać: chartjs.org/docs/latest/general/responsive.html
João Pimentel Ferreira
Oprócz tego ustaw również szerokość i wysokość płótna. Wtedy działa dobrze. Dzięki
Mazhar MIK
63

To, co się dzieje, to Chart.js mnoży rozmiar płótna, gdy jest wywoływany, a następnie próbuje zmniejszyć go z powrotem za pomocą CSS, aby zapewnić wykresy o wyższej rozdzielczości dla urządzeń o wysokiej rozdzielczości.

Problem polega na tym, że nie zdaje sobie sprawy, że już to zrobił, więc gdy wywołuje się kolejne czasy, mnoży już (podwojony lub cokolwiek) rozmiar PONOWNIE, aż wszystko zacznie się psuć. (To, co faktycznie się dzieje, to sprawdzenie, czy powinno dodać więcej pikseli do płótna, zmieniając atrybut DOM dla szerokości i wysokości, jeśli powinien, mnożąc go przez jakiś współczynnik, zwykle 2, następnie zmieniając to, a następnie zmieniając styl css atrybut, aby zachować ten sam rozmiar na stronie.)

Na przykład, jeśli uruchomisz go raz, a szerokość i wysokość obszaru roboczego są ustawione na 300, ustawia je na 600, a następnie zmienia atrybut stylu na 300 ... ale jeśli uruchomisz go ponownie, zobaczy, że szerokość i wysokość DOM wynosi 600 (sprawdź inną odpowiedź na to pytanie, aby zobaczyć, dlaczego), a następnie ustawia ją na 1200, a szerokość i wysokość css na 600.

Nie jest to najbardziej eleganckie rozwiązanie, ale rozwiązałem ten problem, zachowując zwiększoną rozdzielczość dla urządzeń siatkówkowych, po prostu ustawiając szerokość i wysokość płótna ręcznie przed każdym kolejnym wywołaniem Chart.js

var ctx = document.getElementById("canvas").getContext("2d");
ctx.canvas.width = 300;
ctx.canvas.height = 300;
var myDoughnut = new Chart(ctx).Doughnut(doughnutData);
jcmiller11
źródło
Natknąłem się na ten błąd: Uncaught ReferenceError: doughnutData nie jest zdefiniowana
Dulith De Costa
11
Błądzić. tak, to tylko zmienna zastępcza, ponieważ po prostu nie wiem, jakie dane próbujesz wykreślić.
jcmiller11
26

To działa dla mnie:

<body>
    <form>
        [...]
        <div style="position:absolute; top:60px; left:10px; width:500px; height:500px;">
            <canvas id="cv_values"></canvas>

            <script type="text/javascript">
                var indicatedValueData = {
                    labels: ["1", "2", "3"],
                    datasets: [
                        {
                            [...]
                        };

                var cv_values = document.getElementById("cv_values").getContext("2d");
                var myChart = new Chart(cv_values, { type: "line", data: indicatedValueData });
            </script>
        </div>
    </form>
</body>

Zasadniczym faktem jest to, że musimy ustawić rozmiar płótna w znaczniku DIV.

Patrick Pirzer
źródło
Zgodzić się! po prostu umieść płótno wewnątrz div, a następnie upewnij się, że opcja „responsive” NIE jest fałszywa (domyślnie jest prawdziwa). Następnie zastosuj regułę rozmiaru do elementu div.
NoelB
20

W systemach IOS i Android przeglądarka ukrywa pasek narzędzi podczas przewijania, zmieniając w ten sposób rozmiar okna, które prowadzi chartjs do zmiany rozmiaru wykresu. Rozwiązaniem jest zachowanie proporcji.

var options = { 
    responsive: true,
    maintainAspectRatio: true
}

To powinno rozwiązać twój problem.

Pradeep Rajashekar
źródło
6

Jak zasugerował jcmiller11, pomaga ustawienie szerokości i wysokości. Nieco ładniejszym rozwiązaniem jest pobranie szerokości i wysokości płótna przed narysowaniem wykresu. Następnie używając tych liczb do ustawienia wykresu przy każdym kolejnym ponownym losowaniu wykresu. Daje to pewność, że w kodzie javascript nie ma stałych.

ctx.canvas.originalwidth = ctx.canvas.width;
ctx.canvas.originalheight = ctx.canvas.height;

function drawchart() {
    ctx.canvas.width = ctx.canvas.originalwidth;
    ctx.canvas.height = ctx.canvas.originalheight;

    var chartctx = new Chart(ctx);
    myNewBarChart = chartctx.Bar(data, chartSettings); 
}
Zaraz
źródło
Przepraszam, czy możesz wyjaśnić, jak to działa? Na przykład otwieram stronę, a potem płótno ma jeden rozmiar, ale potem, jeśli zmienię rozmiar okna, płótno będzie miało inny rozmiar (i prawdopodobnie nie potrzebuję oryginalnego rozmiaru, ponieważ był dla poprzedniego rozmiaru okna)?
kiradotee
6

Musiałem tu użyć kombinacji wielu odpowiedzi z kilkoma drobnymi poprawkami.

Po pierwsze, konieczne jest zawinięcie elementu canvas w kontenerze blokowym. Mówię wam, nie pozwólcie, aby element canvas miał rodzeństwo; niech będzie samotnym dzieckiem, bo jest uparte i zepsute . (Owijka może nie wymagać żadnych ograniczeń rozmiaru, ale ze względów bezpieczeństwa dobrze jest ustawić maksymalną wysokość).

Po upewnieniu się, że poprzednie warunki są spełnione, podczas inicjowania wykresu upewnij się, że używane są następujące opcje:

var options = { 
    "responsive": true,
    "maintainAspectRatio": false
}

Jeśli chcesz dostosować wysokość wykresu, zrób to na poziomie elementu canvas.

<canvas height="500"></canvas>

Nie próbuj obchodzić się z dzieckiem w żaden inny sposób. Powinno to skutkować satysfakcjonującym, odpowiednio rozplanowanym wykresem, który spokojnie pozostaje w łóżeczku.

truefusion
źródło
3

Miałem podobny problem i znalazłem twoją odpowiedź… W końcu doszedłem do rozwiązania.

Wygląda na to, że źródło Chart.js ma następujące cechy (prawdopodobnie dlatego, że nie powinno ponownie renderować i zupełnie innego wykresu na tym samym płótnie):

    //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
if (window.devicePixelRatio) {
    context.canvas.style.width = width + "px";
    context.canvas.style.height = height + "px";
    context.canvas.height = height * window.devicePixelRatio;
    context.canvas.width = width * window.devicePixelRatio;
    context.scale(window.devicePixelRatio, window.devicePixelRatio);
}

Jest to dobre, jeśli zostanie wywołane raz, ale gdy przerysowujesz wielokrotnie, w końcu wielokrotnie zmieniasz rozmiar elementu Canvas DOM, powodując zmianę rozmiaru.

Mam nadzieję, że to pomoże!

yahfree
źródło
1

Jeśli ktoś ma problemy, znalazłem rozwiązanie, które nie wymaga poświęcania czasu reakcji itp.

Po prostu zawiń płótno w kontenerze div (bez stylów) i zresetuj zawartość div do pustego obszaru roboczego z identyfikatorem przed wywołaniem konstruktora Chart.

Przykład:

HTML:

<div id="chartContainer">
    <canvas id="myChart"></canvas>
</div>

JS:

$("#chartContainer").html('<canvas id="myChart"></canvas>');
//call new Chart() as usual
fpscolin
źródło
1

Próbowałem zmienić rozmiar płótna za pomocą jQuery, ale nie działa dobrze. Myślę, że CSS3 to najlepsza opcja, którą możesz wypróbować, jeśli chcesz ustawić powiększanie na określonym poziomie.

Po opcji najechania kursorem z innego linku do panelu kodu

.style_prevu_kit:hover{
    z-index: 2;
    -webkit-transition: all 200ms ease-in;
    -webkit-transform: scale(1.5);
    -ms-transition: all 200ms ease-in;
    -ms-transform: scale(1.5);   
    -moz-transition: all 200ms ease-in;
    -moz-transform: scale(1.5);
    transition: all 200ms ease-in;
    transform: scale(1.5);
}

Śledź mój link do panelu kodowego:

https://codepen.io/hitman0775/pen/XZZzqN

Hiten Patel
źródło
1

Miałem ten sam problem. Udało mi się to rozwiązać, ustawiając opcję:

responsive: false,
maintainAspectRatio: true,
showScale: false,

A w css ustaw szerokość elementu div kontenera na taką samą jak kanwa:

    #canvasContainer { 
      width: 300px;
    }
    
    canvas {
      width: 300px;
    }

Nova Qiu
źródło
0

Miałem ten sam problem ze skalowaniem, jak przy użyciu Angular CLI. Udało mi się go uruchomić, usuwając ten wiersz z pliku index.html:

<script src="node_modules/chart.js/dist/Chart.bundle.min.js"></script>

a następnie w pliku angular-cli.json, w sekcji skryptów, używając tego:

"scripts": ["../node_modules/chart.js/dist/Chart.bundle.min.js"]

Źródło : mikebarr58

Wouter Vanherck
źródło
-4

Dodaj, diva to rozwiąże problem

<div style="position:absolute; top:50px; left:10px; width:500px; height:500px;"></div>
rishabh bhardwaj
źródło
-6
 let canvasBox = ReactDOM.findDOMNode(this.refs.canvasBox);
 let width = canvasBox.clientWidth;
 let height = canvasBox.clientHeight;
 let charts = ReactDOM.findDOMNode(this.refs.charts);
 let ctx = charts.getContext('2d');
 ctx.canvas.width = width;
 ctx.canvas.height = height;
 this.myChart = new Chart(ctx);
Robin ma
źródło