How get items size in pixels?

Hello!
How get any items (ex HorizontalLayout ) size in pixels. The functions getHeight or getWidth return size in percents, of course becouse before size sets with setWidth in percents, but how get real size in pixels?

The
CSS Tools add-on
fits the bill, but I haven’t updated it for Vaadin 7 or 8. Contributions are very welcome if someone wants to migrate the add-on for newer versions! I can even donate the add-on if someone wants to start maintaining it.


SizeReporter
should do it as well. It hasn’t been updated to Vaadin 8 either, but I think there’s nothing that relies on Vaadin 8 particulars so it could even work out of the box (or rebuilding it from source code should be trivial).

-Olli

Thanks for answers.
I do it this way:

VerticalLayout panel = new VerticalLayout();
panel.setId("TestPanel");
JavaScript.getCurrent().addFunction("getElSize",                
                       (arg) -> {
                              int width = (int) arg.getNumber(0);                    
                              int height = (int) arg.getNumber(1);                    
                              Notification.show("width: " + width + ", height: " + height, Notification.Type.TRAY_NOTIFICATION);                
                       });
JavaScript.getCurrent().execute(" var elem = document.getElementById('" + panel.getId() +"'); " +
                                                    " if(elem){ getElSize(elem.clientWidth, elem.clientHeight); }");

That should work, too, at least if you don’t need automatic updates when the screen size changes.

-Olli

Hi,
The SizeReporter hasn’t been updated for Vaadin 14+ so, it’s useless for this version of vaadin. It would be great to have a function like: component.getElementWidth or component getElementHeight.

This should be a very basic function for a so great framework as vaadin is.

Cheers, Simone

You can do this to retrieve the client height or width:


@Route("width")
public class WidthView extends VerticalLayout {

    public WidthView() {
        Button button = new Button("display width/height");
        button.setWidth("45%");
        button.addClickListener(event -> {
           button.getElement().executeJs("$0.$server.displaySize($1.clientWidth, $1.clientHeight)", getElement(), button.getElement());
        });
        Button anotherExampleButton = new Button("display width");
        anotherExampleButton.setWidth("45%");
        anotherExampleButton.addClickListener(event -> {
            anotherExampleButton.getElement()
                    .executeJs("return $0.clientWidth", anotherExampleButton.getElement()).then( width -> {
                Notification.show("Button width "+ width.asNumber());
            });
        });

        add(button,anotherExampleButton);
    }

    @ClientCallable
    public void displaySize(int width, int height) {
        Notification.show("Button width "+ width + " height "+ height);
    }
}

In this example you have 2 ways of retrieving the width:
1/ The Java calls Javascript that calls an available Java function (displaySize) and gives the client size.
2/ The Java calls Javascript that returns the width of the button.

Both calls are asynchronous since the height/width information are on the client side.

Maybe there are a different way of doing this, can you explain your usecase?

Hi Jean-Christophe,
Thank you for your answer.
My usecase is, that I have to listen on window resize event and then I have to know the width of one of my Divs. So like Olli Tietäväinen says, “That should work, too, at least if you don’t need automatic updates when the screen size changes”. And I have to do exact this thing. So I tried this in my View:

	Div myDiv = new Div();
	myDiv.setClassName("my-div");
	
	... omit further code

	@Override
	protected void onAttach (AttachEvent attachEvent) {
		super.onAttach(attachEvent);
		initializeView();
		initAppBar();
		UI.getCurrent().getPage().setTitle("My Title");
		getUI().ifPresent(ui -> {
			Page page = ui.getPage();
			resizeListener = page.addBrowserWindowResizeListener(event -> updateOnResize(event.getWidth()));
			page.retrieveExtendedClientDetails(details -> updateOnResize(details.getBodyClientWidth()));
		});
	}
	
	private void updateOnResize (int windowsWidth) {
	  // get width of myDiv over javascript async... 
	  // check wheter windowsWidth is less then (for example) 1024px and myDivWidth < 300px
	  getElementWidthPromiseByClassName("my-div").then(result -> {
		  if (windowsWidth <= 1024 && Integer.parseInt(result.toString()) >= 300) {
			  // do stuff here
		  }
	  });
	}
	
	public static PendingJavaScriptResult getElementWidthPromiseByClassName (String className) {
		Page page = UI.getCurrent().getPage();
		return page
			.executeJs(
				"return document.getElementsByClassName($0)[0]
.offsetWidth;",
				className);
	}

But this is not working, then I get an access error, because both calls (on resize and client width) are in separate threads.

I hope I could explain my situation.

Best Regards
Simone

Hi,

I can check your code, but you can try this add-on:
https://vaadin.com/directory/component/mediaquery
(disclaimer I’m the author of the add-on)

I think it can help you and your code will be much easier to maintain.

I can try to do an example of your usecase with the media query addon (since the condition is a mix of condition of the element and the window).

I’ve updated the add-on and add an example for your usecase.

/**Change the color of a div is the window size < 1024px and div width < 300px **/
@Route("mediaquery")
public class MediaQueryView extends VerticalLayout {

    private boolean div300pxOrLess = false;
    private boolean window1024OrLess = false;
    private Div div;
    private Span textWindow;
    private Span textDiv;

    public MediaQueryView() {
        setSizeFull();
        div = new Div();
        div.setWidth("50%");
        div.setHeight("100px");
        textWindow = new Span("window1024OrLess");
        textDiv = new Span("div300pxOrLess");
        add(div, textWindow, textDiv);
        CustomMediaQuery customMediaQuery1024 = new CustomMediaQuery(this::updateWindows1024OrLess);
        add(customMediaQuery1024);
        customMediaQuery1024.setQuery(new MediaQuery(new WidthAttributes.MaxWidth("1024px")));
        ElementMediaQuery elementMediaQuery300 = new ElementMediaQuery(this::updateDiv300OrLess);
        elementMediaQuery300.setElement(div);
        elementMediaQuery300.setQuery(new MediaQuery(new WidthAttributes.MaxWidth("300px")));
        add(elementMediaQuery300);
    }

    private void updateWindows1024OrLess(Boolean window1024OrLess) {
        this.window1024OrLess = window1024OrLess;
        textWindow.setVisible(window1024OrLess);
        updateCondition();
    }

    private void updateDiv300OrLess(Boolean div300pxOrLess) {
        this.div300pxOrLess = div300pxOrLess;
        textDiv.setVisible(div300pxOrLess);
        updateCondition();
    }
    private void updateCondition() {
        if (window1024OrLess && div300pxOrLess) {
            div.getStyle().set("background-color", "green");
        } else {
            div.getStyle().set("background-color", "red");
        }
    }

}

Hi Jean-Christophe,

Thank you very much for your reply. That helped. Great!!