Highcharts: Le conteneur Flex ne redimensionne pas correctement les graphiques si vous avez plusieurs graphiques dans un conteneur Flex.

Créé le 2 mars 2017  ·  18Commentaires  ·  Source: highcharts/highcharts

Comportement attendu

Si vous avez un conteneur flexible avec CSS
affichage : flexible ;
flex-direction : rangée ;

et 4 enfants avec
flex-croissance : 1 ;
base flexible
Vous vous attendez à avoir une ligne avec 4 graphiques, chaque taille représentant 25 % du parent.

Comportement réel

Le comportement réel dépend de la taille du parent qu'il pourrait être
4 éléments dans une rangée avec 25 % (comportement attendu)
3 articles de petite taille dans une rangée et 100 % article sur la rangée suivante.
4 rangées avec 100 % d'articles à l'intérieur.

Démo en direct avec étapes à reproduire

http://jsfiddle.net/xLz8tcrc/1/

Navigateur(s) concerné(s)

Chrome
Firefox

Undecided

Commentaire le plus utile

@KacperMadej
eh bien, svg est un graphique vectoriel. Cela signifie que mettre la largeur et la hauteur SVG à 100% ne devrait pas avoir d'effet négatif sur le rendu, corrigez-moi si je me trompe.

J'ai réussi à remplacer le CSS interne svg largeur de l'élément

highcharts-chart::ng-deep {
  .highcharts-container,
  .highcharts-container svg {
     width: 100% !important;
     height: 100% !important;
  }
}

Cela fonctionne assez bien maintenant.

Tous les 18 commentaires

Dans votre démo, j'ai ajouté un extrait pour exécuter chart.reflow() après avoir redimensionné la boîte flexible. Cela est nécessaire, car les graphiques ne se redistribuent automatiquement que lorsque la _fenêtre_ est redimensionnée.

De plus, l'ajout de overflow: hidden aux conteneurs du graphique garantit que le conteneur peut être plus petit que le graphique, ce qui les empêche d'être trop larges lors de la réduction.

Cela résout-il votre problème ? http://jsfiddle.net/xLz8tcrc/2/

Merci pour votre réponse.
L'utilisation de chart.reflow() ressemble plus à une solution de contournement qu'à une solution au problème d'origine. Ce sera beaucoup plus simple si HighCharts se redimensionne correctement selon les règles CSS de l'élément parent.

J'ai posté juste un exemple, dans un cas d'utilisation réel, nous voulons que les graphiques soient redimensionnés lors du redimensionnement de la fenêtre ou du redimensionnement de l'élément parent, il n'est donc pas si facile d'implémenter une logique où vous pouvez appeler chart.reflow(). Pour le redimensionnement de fenêtre, c'est plus simple, en utilisant simplement l'événement de redimensionnement de fenêtre.
Pour les autres composants, nous devons implémenter une sorte d'interface redimensionnable pour un composant parent, nous pouvons donc appeler chart.reflow lors du redimensionnement, cela peut fonctionner dans certains cas, mais pas sûr de tous.

Pouvez-vous s'il vous plaît ne pas fermer le ticket pour l'instant, je vais essayer de mettre en œuvre votre approche ou peut-être que quelqu'un a d'autres idées.

Ce que vous décrivez est fondamentalement le même problème que nous avons en interne dans Highcharts. Nous effectuons actuellement des refusions automatiques lors du redimensionnement de la fenêtre. Idéalement, nous aimerions également effectuer des redistributions automatiques sur le redimensionnement des éléments contenants, mais il n'existe actuellement aucun moyen efficace d'écouter les changements de taille des éléments DOM.

Voir http://stackoverflow.com/questions/6492683/how-to-detect-divs-dimension-changed pour une discussion, et le même sujet a également été discuté précédemment dans ce forum. Comme mentionné dans le fil de discussion, le seul moyen possible semble actuellement d'utiliser setTimeout ou requestAnimationFrame , qui gaspillent tous deux du CPU.

Avez-vous jeté un œil au ResizeSensor mentionné dans le post StackOverflow auquel vous êtes lié (https://github.com/marcj/css-element-queries) ? Il utilise quelques éléments DOM supplémentaires et un écouteur d'événement scroll pour détecter les redimensionnements. Il utilise uniquement requestAnimationFrame pour limiter le nombre d'événements de redimensionnement envoyés (max 1 par image).

Il y a aussi http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/ qui décrit comment accomplir cela en utilisant une balise object , qui déclenche par coïncidence un événement resize lorsque sa taille change.

À l'avenir, ResizeObserver seront implémentés dans les navigateurs, mais ce n'est pas faisable pour le moment. Il existe plusieurs polyfills répertoriés sur https://github.com/WICG/ResizeObserver/issues/3, mais ils semblent s'appuyer sur des MutationObeserver et des sondages ou d'autres approches inutiles.

À mon avis, Highcharts ne devrait pas implémenter de telles astuces dans le noyau. L'écouteur de redimensionnement de fenêtre couvre la plupart des cas, puis nous avons le crochet chart.reflow pour permettre aux implémenteurs de couvrir d'autres cas, lorsqu'un élément est redimensionné sans redimensionnement de fenêtre. Donc, si vous avez testé l'une des approches ci-dessus et que cela fonctionne pour votre cas, je vous suggère de l'utiliser avec chart.reflow .

+1 Nous venons de rencontrer ce problème, il a fallu une éternité pour réaliser que le problème était la flexbox.

l'une des raisons pour lesquelles j'arrête d'utiliser flex ... le redimensionnement ne fonctionne jamais comme prévu, même merde pour la grille d'affichage

afficher le bloc en ligne est bien meilleur

l'une des raisons pour lesquelles j'arrête d'utiliser flex ... le redimensionnement ne fonctionne jamais comme prévu, même merde pour la grille d'affichage

c'est juste une autre solution de contournement.

Y a-t-il des mises à jour à ce sujet ? Est-il prévu de réparer ce @TorsteinHonsi ?

Je commence à utiliser Highcharts dans des projets angulaires et j'ai également rencontré cela.
Ce que je ne comprends pas, c'est que le graphique est en fait SVG . Il ne devrait donc pas y avoir de problème pour le mettre à 100% de sa taille. Au lieu de cela, il semble que la largeur et la hauteur soient explicitement définies directement sur svg.

capture

Salut @GeorgeKnap

Pourriez-vous fournir une démonstration en direct avec Highcharts et un SVG non Highcharts pour montrer ce que vous avez en tête ? Comment cela influencera-t-il la mise à l'échelle et la précision des pixels du rendu net ?

@KacperMadej
eh bien, svg est un graphique vectoriel. Cela signifie que mettre la largeur et la hauteur SVG à 100% ne devrait pas avoir d'effet négatif sur le rendu, corrigez-moi si je me trompe.

J'ai réussi à remplacer le CSS interne svg largeur de l'élément

highcharts-chart::ng-deep {
  .highcharts-container,
  .highcharts-container svg {
     width: 100% !important;
     height: 100% !important;
  }
}

Cela fonctionne assez bien maintenant.

Merci d'avoir partagé la solution.

Le problème avec la mise à l'échelle de SVG est que cela pourrait provoquer un rendu flou car la précision des pixels pourrait être perdue. Un autre problème pour une solution Highcharts générale est la prise en charge des navigateurs hérités (ce n'est pas un bloqueur, nous devrons juste nous assurer que nous avons un polyfill approprié).

J'ai approfondi ce problème et j'ai trouvé trois problèmes :

  1. Lors de la détermination de la taille du conteneur, Highcharts utilise scrollWidth , qui est arrondi au cas où la largeur réelle est inférieure au pixel. Dans le violon d'origine, le premier graphique est dessiné avec une fraction de pixel trop large et la disposition flexible passe de 4 colonnes à 3 colonnes. Ceci est corrigé dans le commit ci-dessus en utilisant Math.floor et element.getBoundingClientRect .

  2. Lors de la réduction de la largeur de la page ou du conteneur, les graphiques seraient plus larges que les 25 % qui leur sont attribués, rompant ainsi la mise en page. Ceci est corrigé dans le commit ci-dessus en ajoutant overflow:hidden au conteneur de graphique de niveau supérieur.

  3. Lors de la mise à l'échelle vers le haut ou vers le bas du conteneur flexible _sans_ redimensionner la fenêtre, les graphiques ne seront pas mis à l'échelle. Ils ne le feront toujours pas, mais au moins maintenant, ils ne cassent pas la mise en page. La solution de @GeorgeKnap peut fonctionner pour certains, mais comme le dit Kacper, cela peut entraîner des graphiques flous, en plus de redimensionner la hauteur, cela ne respecterait pas la taille de la police, etc. Voir http://jsfiddle.net/highcharts/xLz8tcrc/219 / et la même configuration avec un appel chart.reflow explicite : http://jsfiddle.net/highcharts/xLz8tcrc/221/. La solution souhaitée serait d'écouter un événement lorsque le conteneur div est redimensionné, mais pour l'instant, le seul événement natif de ce type est le ResizeObserver Chrome.

Ma solution de remplacement CSS ci-dessus a causé des problèmes majeurs avec la position de la souris (info-bulle). Pour résoudre ce problème, j'ai complètement supprimé le remplacement CSS et implémenté ResizeObserver . Il observe la taille de l'élément parent et modifie les propriétés width et height directement dans les options du graphique :

Il s'agit de la solution angulaire, donc on utilise ElementRef pour accéder à l'élément DOM natif et ChangeDetectorRef pour déclencher la vérification des modifications :

    const resizeObserver = new ResizeObserver(debounce((data: Array<ResizeObserverEntry>) => {
      if (this.chartOptions) {
        const options = { ...this.chartOptions } as Highcharts.Options;
        options.chart!.height = data[0].contentRect.height;
        options.chart!.width = data[0].contentRect.width;
        this.chartOptions = options;
        this.cd.markForCheck();
      }
    }, 200));
    resizeObserver.observe(this.elementRef.nativeElement.children[0]);

Merci d'avoir partagé! Voici un plugin général qui répond à l'option chart.reflow et délie le gestionnaire intégré window.onresize si ResizeObserver est pris en charge :

// Generic plugin that adds support for listening to container resize rather than
// window resize. As of 2018 only Chrome supports ResizeObserver.
Highcharts.wrap(Highcharts.Chart.prototype, 'setReflow', function(proceed, reflow) {

    var chart = this;

    proceed.call(this, reflow);

    if (reflow !== false && typeof ResizeObserver === 'function') {

        // Unbind window.onresize handler so we don't do double redraws
        if (this.unbindReflow) {
            this.unbindReflow();
        }

        var ro = new ResizeObserver(function () {
            chart.reflow();
        });

        ro.observe(this.renderTo);
    }
});

Regardez-le en direct sur jsFiddle .

Chart1
chart2
Salut,

Je suis nouveau dans l'utilisation de highcharts, dans ces captures d'écran ci-jointes, vous pouvez clairement voir que le graphique dépasse la largeur du conteneur. J'ai plusieurs graphiques sur la même page qui s'ouvrent lorsque je clique sur l'accordéon. À chaque chargement initial, la largeur du graphique dépasse la largeur du conteneur.
existe-t-il une solution à ce problème ?

ci-dessous est le code concernant l'accordéon.

fonction initsectionclicks (conteneur) {
$('.fe-section-accordion-header', conteneur).click(function () {
var parentcontainer = $(this).parent();
var accordioncontainer = $(parentcontainer).find('.fe-section-accordion-container');

        if (accordioncontainer != null)
        {
            var accordioncontainerOpen = accordioncontainer.is(':visible');

            accordioncontainer[accordioncontainerOpen ? 'slideUp' : 'slideDown'](400, "swing", function() {
                ToolkitUI.Common.ResizeIFrame();
                var highChartsWrapper = $('.fe-section-chart-wrap', accordioncontainer);
                if (highChartsWrapper.length) {
                    $.each(highChartsWrapper,
                        function(index, obj) {
                            var hcObj = $(obj).highcharts();
                            if (hcObj)
                                hcObj.reflow();
                        });
                }
            });

            if (!accordioncontainerOpen)
            {
                $(accordioncontainer).ShowLoadingInsideContainer();
            }

            $(parentcontainer).find('.fe-expandcollapse').toggleClass("fe-icon-expand", accordioncontainerOpen).toggleClass("fe-icon-collapse", !accordioncontainerOpen);
            $('.fe-section-accordion-header', parentcontainer).toggleClass('highlight', !accordioncontainerOpen);
        }

        $(window).resize();
    });

    //we have to unbind any click event handlers before attaching a new one, as without unbind we will be attaching the same handler multiple times.
    //this is because we are binding the data from the start for each tab when it is clicked, which rebinds the same method again and again.
    $('.fe-accordion-expandcollapse-all', container).unbind('click').click(function () {
        var isallopen = $(this).hasClass('fe-accordion-collapse');
        var counter = 1;
        $(this).toggleClass('fe-accordion-expand', isallopen).toggleClass('fe-accordion-collapse', !isallopen);
        $('.fe-expandcollapse', container).toggleClass('fe-icon-expand', isallopen).toggleClass('fe-icon-collapse', !isallopen);
        $('.fe-section-accordion-header', container).toggleClass('highlight', !isallopen);
        $('.fe-section-accordion-container')[isallopen ? 'slideUp' : 'slideDown'](400, "swing", function () {
            if (counter == $('.fe-section-accordion-container').length) {
                ToolkitUI.Common.ResizeIFrame();
            }
            counter++;
        });

        if (!isallopen)
        {
            $('.fe-section-accordion-container').ShowLoadingInsideContainer();

        }
        $(window).resize();
    });
};

@Nagaraj2106

Veuillez ajouter une démonstration en direct pour le problème, afin que nous puissions recréer le problème, le déboguer et tester les solutions et solutions de contournement possibles. Veuillez également vérifier la solution de contournement suggérée dans ce commentaire : https://github.com/highcharts/highcharts/issues/6427#issuecomment -438212322

Ni l'appel de reflow() lors du redimensionnement de la fenêtre ni l'utilisation du plugin n'ont résolu le problème pour moi ; Cependant, cette réponse de SO l'a fait.

J'utilise highcharts dans un conteneur flex bootstrap 4. Le graphique se redimensionne (plus large) mais ne se redimensionne pas à moins que je rende le conteneur absolu :

<div id="chart-container">
    <div id="chart"></div>
</div>

avec le CSS :

#chart-container {
    position: relative;
    width: 100%;
    height: 280px;
}

#chart {
    position: absolute;
    width: 100%;
}

J'ai attaché le graphique à #chart avec renderTo: 'chart' .

Cette page vous a été utile?
0 / 5 - 0 notes