Highcharts: El contenedor flexible no cambia el tamaño de los gráficos correctamente, si tiene varios gráficos dentro de un contenedor flexible.

Creado en 2 mar. 2017  ·  18Comentarios  ·  Fuente: highcharts/highcharts

Comportamiento esperado

Si tiene un contenedor flexible con css
pantalla: flex;
dirección flexible: fila;

y 4 niños con
crecimiento flexible: 1;
base flexible
Espera tener una fila con 4 gráficos, cada tamaño del 25% del padre.

Comportamiento real

El comportamiento real depende del tamaño del padre que podría ser
4 ítems en una fila con 25% (comportamiento esperado)
3 artículos de tamaño pequeño en una fila y artículo 100% en la siguiente fila.
4 filas con elementos 100% en su interior.

Demostración en vivo con pasos para reproducir

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

Navegadores afectados

Cromo
Firefox

Undecided

Comentario más útil

@KacperMadej
bueno, svg es un gráfico vectorial. Eso significa que poner el ancho y la altura de SVG al 100% no debería tener ningún efecto negativo en el renderizado, corrígeme si me equivoco.

Me las arreglé para anular el ancho del elemento interno svg CSS:

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

Funciona razonablemente bien ahora.

Todos 18 comentarios

En su demostración, agregué un fragmento para ejecutar chart.reflow() después de cambiar el tamaño del cuadro flexible. Esto es necesario, ya que los gráficos solo se reajustan automáticamente cuando la _ventana_ cambia de tamaño.

Además, agregar overflow: hidden a los contenedores del gráfico asegura que el contenedor pueda ser más pequeño que el gráfico, lo que evita que sean demasiado anchos al reducir la escala.

¿Esto resuelve su problema? http://jsfiddle.net/xLz8tcrc/2/

Gracias por su respuesta.
El uso de chart.reflow () parece más una solución que una solución al problema original. Será mucho más sencillo si HighCharts cambia de tamaño correctamente de acuerdo con las reglas CSS del elemento padre.

He publicado solo un ejemplo, en el caso de uso real, queremos que los gráficos cambien de tamaño al cambiar el tamaño de la ventana o al cambiar el tamaño del elemento principal, por lo que no es tan fácil implementar la lógica donde puede llamar a chart.reflow (). Para el cambio de tamaño de la ventana es más menos sencillo, simplemente usando el evento de cambio de tamaño de la ventana.
Para otros componentes, necesitamos implementar algún tipo de interfaz redimensionable para un componente principal, por lo que podemos llamar a chart.reflow al cambiar el tamaño, eso podría funcionar en algunos casos, pero no estoy seguro de todos ellos.

¿Pueden no cerrar el boleto por ahora? Intentaré implementar su enfoque o tal vez alguien tenga otras ideas.

Lo que está describiendo es básicamente el mismo problema que tenemos internamente en Highcharts. Actualmente hacemos reflujos automáticos al cambiar el tamaño de la ventana. Idealmente, también nos gustaría hacer reflujos automáticos al cambiar el tamaño del elemento contenedor, pero actualmente no hay una forma efectiva de escuchar los cambios de tamaño del elemento DOM.

Consulte http://stackoverflow.com/questions/6492683/how-to-detect-divs-dimension-changed para una discusión, y el mismo tema también se discutió anteriormente en este foro. Como se menciona en el hilo, la única forma posible actualmente parece ser usando setTimeout o requestAnimationFrame , los cuales están desperdiciando CPU.

¿Echó un vistazo al ResizeSensor mencionado en la publicación de StackOverflow a la que se vinculó (https://github.com/marcj/css-element-queries)? Utiliza un par de elementos DOM adicionales y un detector de eventos scroll para detectar cambios de tamaño. Solo usa requestAnimationFrame para limitar la cantidad de eventos de cambio de tamaño que se envían (máximo 1 por cuadro).

También hay http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/ que describe cómo lograr esto usando una etiqueta object , que casualmente dispara un evento resize cuando cambia su tamaño.

En el futuro, habrá ResizeObserver implementados en los navegadores, pero eso no es factible en este momento. Hay varios polyfills para los que se enumeran en https://github.com/WICG/ResizeObserver/issues/3 pero parecen depender de MutationObeserver y encuestas u otros enfoques derrochadores.

En mi opinión, Highcharts no debería implementar trucos como este en el núcleo. El oyente de cambio de tamaño de ventana cubre la mayoría de los casos, luego tenemos el gancho chart.reflow para permitir que los implementadores cubran otros casos, cuando un elemento cambia de tamaño sin un cambio de tamaño de ventana. Entonces, si probó uno de los enfoques anteriores y funciona para su caso, le sugiero que lo use junto con chart.reflow .

+1 Acabamos de llegar a este problema, tardamos una eternidad en darnos cuenta de que el problema era flexbox.

una de las razones por las que dejo de usar flex ... el cambio de tamaño nunca funciona como se esperaba, la misma mierda para la cuadrícula de visualización

mostrar bloque en línea es mucho mejor

una de las razones por las que dejo de usar flex ... el cambio de tamaño nunca funciona como se esperaba, la misma mierda para la cuadrícula de visualización

esta es solo otra solución.

¿Hay alguna actualización sobre esto? ¿Hay planes para arreglar esto @TorsteinHonsi ?

Estoy empezando a usar Highcharts en proyectos angulares y también me he encontrado con esto.
Lo que no entiendo es que el gráfico es en realidad SVG . Así que no debería haber ningún problema para ponerlo al 100% del tamaño. En cambio, parece que el ancho y el alto se establecen explícitamente directamente en svg.

capture

Hola @GeorgeKnap

¿Podría proporcionar una demostración en vivo con Highcharts y un SVG que no sea de Highcharts para mostrar lo que tiene en mente? ¿Cómo influirá esto en la escala y la precisión de píxeles de la representación nítida?

@KacperMadej
bueno, svg es un gráfico vectorial. Eso significa que poner el ancho y la altura de SVG al 100% no debería tener ningún efecto negativo en el renderizado, corrígeme si me equivoco.

Me las arreglé para anular el ancho del elemento interno svg CSS:

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

Funciona razonablemente bien ahora.

Gracias por compartir la solución.

El problema de escalar SVG es que esto podría causar un renderizado borroso ya que podría perderse la precisión de los píxeles. Otro problema para una solución general de Highcharts es la compatibilidad con navegadores heredados (no es un bloqueador, solo necesitaremos asegurarnos de tener un polyfill adecuado).

Hice un análisis profundo de este problema y encontré tres problemas:

  1. Al determinar el tamaño del contenedor, Highcharts usa scrollWidth , que se redondea hacia arriba en caso de que el ancho real sea subpíxel. En el violín original, esto da como resultado que el primer gráfico se dibuje una fracción de píxel demasiado ancho y el diseño flexible salte de 4 columnas a 3 columnas. Esto se corrige en la confirmación anterior usando Math.floor y element.getBoundingClientRect .

  2. Al reducir el ancho de la página o el contenedor, los gráficos serían más anchos que el 25% asignado a ellos, rompiendo así el diseño. Esto se corrige en la confirmación anterior agregando overflow:hidden al contenedor del gráfico de nivel superior.

  3. Al escalar hacia arriba o hacia abajo el contenedor flexible _sin_ cambiar el tamaño de la ventana, los gráficos no se escalarán. Todavía no lo harán, pero al menos ahora no rompen el diseño. La solución de @GeorgeKnap puede funcionar para algunos, pero como dice Kacper, puede resultar en gráficos borrosos, además de que también cambiará el tamaño de la altura, faltaría el respeto al tamaño de la fuente, etc. Ver http://jsfiddle.net/highcharts/xLz8tcrc/219 / y la misma configuración con una llamada chart.reflow explícita: http://jsfiddle.net/highcharts/xLz8tcrc/221/. La solución deseada sería escuchar un evento cuando se cambia el tamaño del div contenedor, pero por ahora el único evento nativo de este tipo es el ResizeObserver Chrome.

Mi solución de anulación de CSS anterior causó problemas importantes con la posición del mouse sobre (información sobre herramientas). Para solucionarlo, eliminé completamente la anulación de CSS e implementé ResizeObserver . Observa el tamaño en el elemento principal y cambia las propiedades width y height directamente en las opciones del gráfico:

Esta es la solución angular, por lo que se usa ElementRef para acceder al elemento DOM nativo y ChangeDetectorRef para activar la verificación de cambio:

    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]);

¡Gracias por compartir! Aquí hay un complemento general que responde a la opción chart.reflow y desvincula el controlador window.onresize incorporado si se admite ResizeObserver :

// 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);
    }
});

Véalo en vivo en jsFiddle .

Chart1
chart2
Hola,

Soy nuevo en el uso de gráficos altos, en esas capturas de pantalla adjuntas, se puede ver claramente que el gráfico excede el ancho del contenedor. Tengo muchos gráficos en la misma página que se abren cuando hago clic en el acordeón. En cada carga inicial, el ancho del gráfico excede el ancho del contenedor.
¿Hay alguna solución para este problema?

a continuación se muestra el código sobre el acordeón.

function initsectionclicks (contenedor) {
$ ('. fe-section-accordion-header', contenedor) .click (function () {
var parentcontainer = $ (esto) .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

Agregue una demostración en vivo para el problema, para que podamos recrear el problema, depurarlo y probar posibles soluciones y soluciones. Además, verifique la solución alternativa sugerida en este comentario: https://github.com/highcharts/highcharts/issues/6427#issuecomment -438212322

Ni llamar a reflow () en el cambio de tamaño de la ventana ni usar el complemento resolvió el problema para mí; sin embargo, esta respuesta de SO lo hizo.

Estoy usando highcharts en un contenedor flexible bootstrap 4. El gráfico cambia de tamaño hacia arriba (más ancho) pero no cambia de tamaño hacia abajo a menos que haga que el contenedor sea absoluto:

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

con el CSS:

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

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

Adjunté el gráfico a #chart con renderTo: 'chart' .

¿Fue útil esta página
0 / 5 - 0 calificaciones