syampillai / SOCharts

A wrapper around the "echarts" JavaScript library to use it as a Vaadin component.
Apache License 2.0
27 stars 11 forks source link

Missing resize handling #24

Closed norbertroamsys closed 6 months ago

norbertroamsys commented 1 year ago

Not sure whether this is a bug, missing feature or wrong usage...

We use SOChart for generating a line chart using the following code:

    private Component createChart(final Map<LocalDateTime, BigDecimal> powerMap) {
        final SOChart soChart = new SOChart();

        // fill in data values
        final TimeData xValues = new TimeData();
        final Data yValues = new Data();
        powerMap.entrySet().forEach(entry -> {
            xValues.add(entry.getKey());
            yValues.add(DecimalValues.divideByInt(entry.getValue(), 1000));
        });

        xValues.setName("Uhrzeit");
        yValues.setName("Werte");

        final LineChart lineChart = new LineChart(xValues, yValues);
        lineChart.setName(getTranslation("Leistung (AC)");
        lineChart.setColors(new Color(255, 193, 37));
        lineChart.setSmoothness(true);
        lineChart.getAreaStyle(true).setColor(new Color(255, 193, 37));
        lineChart.getPointSymbol(true).setType(PointSymbolType.ROUND_RECTANGLE);

        final XAxis xAxis = new XAxis(DataType.TIME);
        xAxis.setMinAsMinData();

        final YAxis yAxisLeft = new YAxis(DataType.NUMBER);
        yAxisLeft.setName("kW");
        yAxisLeft.setNameLocation(Location.MIDDLE);
        yAxisLeft.setNameRotation(90);
        yAxisLeft.setNameGap(35);
        yAxisLeft.setMin(0);
        yAxisLeft.setMaxAsMaxData();

        final RectangularCoordinate rc = new RectangularCoordinate(xAxis, yAxisLeft);
        lineChart.plotOn(rc);

        soChart.add(lineChart);
        return soChart;
    } 

The created chart is inserted into a VerticalLayout as last component (see screenshot). This VerticalLayout panel is switched to different height and width by media queries in CSS. Our problem is that the chart (div, canvas) does not resize dependent to its parent. I have provided a screenshot to demonstrate the effect and also show part of the DOM.

We noticed that this behavior is different in the ECharts Demo for the same chart type: As you can see the chart is resized to its parent container properly.

Is there a way to do this in SOChart? We noticed that width and height is set maybe by the frontend JS code for the nested divs and the canvas element.

Please note that we are currently using so-charts version 2.3.0 because of a dependency to Java 11. But as far as I see there is also no support in version 3.2.1

Thanks for your feedback and support!

chart-resize-problem

norbertroamsys commented 1 year ago

In the meantime we investigated in some workaround to get the resizing working. What we found out:

Following this rules it seems that the initial size is fine then.

But the dynamic resizing does not work: The chart does not change it's size if the parent container gets a new size. We implemented a BrowserResizeEventHandler as a workaround. To force the resizing on event we toggle the percentage between 100% and 99.9%.

All this workaround code is encapsulated in an Helper called ChartResizer:

import com.storedobject.chart.SOChart;
import com.vaadin.flow.shared.Registration;
import java.util.Objects;

/**
 * Helper for forcing (re)sizing after create and on browser window resize events.
 *
 * @author nbecker
 */
public class ChartResizer {

    private static final String FULL_SIZE = "100%";

    private final SOChart chart;
    private Registration resizeRegistration;

    /**
     * Wraps the chart for resize handling.
     *
     * @param chart the chart
     */
    public static void wrap(final SOChart chart) {
        new ChartResizer(chart);
    }

    private ChartResizer(final SOChart chart) {
        this.chart = chart;

        setSize(FULL_SIZE);
        chart.addAttachListener(event -> {
           resizeRegistration = event.getUI().getPage().addBrowserWindowResizeListener(resizeEvent -> adjustSize());
        });
        chart.addDetachListener(event -> {
            if (resizeRegistration != null) {
                resizeRegistration.remove();
                resizeRegistration = null;
            }
        });
    }

    private void adjustSize() {
        if (Objects.equals(chart.getHeight(), FULL_SIZE)) {
            // set a different value to force resizing
            setSize("99.9%");
        } else {
            setSize(FULL_SIZE);
        }
    }

    private void setSize(final String size) {
        chart.setWidth(size);
        chart.setHeight(size);
        chart.setMinWidth(size);
        chart.setMinHeight(size);
        chart.setMaxWidth(size);
        chart.setMaxHeight(size);
    }

}

A call to ChartResizer.wrap(myChart) will initially resize the chart and install the event handler.

We hope this information is useful for you to find a much better solution. Maybe one option can be to make the EChart.resize() function accessible via the SOChart server wrapper?

norbertroamsys commented 1 year ago

It seems that this issue has been resolved in https://github.com/syampillai/SOCharts/pull/9 in the past. So our problem is that we have to use version 2.3.0 by now (because of Java 11). @syampillai : If this is the case you can close this issue of cause.

syampillai commented 6 months ago

Yes, this was resolved in an earlier release.