I've got one lit-element, inner-element, slotted into another lit-element, outer-element. For flexibility, the outer-element gets to set the width and height of the inner-element using CSS. The inner-element needs to know it's width and height to determine how to draw its SVG content.
How can inner-element reliably learn its own width and height across browsers?
I've got a live example here:
https://stackblitz.com/edit/7pkfkx-j9rnx9
I'm using updated() to get the width/height based on this very helpful information:
https://github.com/Polymer/lit-element/issues/507#issuecomment-459546838
In Chrome, the example works fine - the SVG displays "width = 150 height = 100". But in Edge, I get "width = 300 height = 303.8". Note that even in Edge, the inner-element ends up having the correct width and height (150x100), it just seems to be getting there after updated() has been called.
I don't have access to Edge in order to confirm, but there are a few things you might be interested in testing here.
1) In your index.ts you have the following code:
import './inner-element.js';
import './outer-element.js';
This means that the inner element, will register and upgrade before the outer element has been registered and upgraded, which means that its size will be determined initially as if outer-element is a div, and then subsequently be granted the slotted styles inside of outer-element. Swap the imports to prevent this specific race order from occuring.
2) You are measuring in firstUpdated() which can technically happen before the element hit's the page, meaning that you are measuring an unrendered element, which is an element that has no size. Waiting until connectedCallback() can ensure that you are measuring the element "in page".
3) Measuring the element synchronously means you might be measuring before all of the parent based/classed based/etc code has been run, using requestAnimationFrame() in connectedCallback() can help ensure that you aren't measuring until you can be 100% sure that the element is ready to be measured.
Try this demo out to confirm: https://stackblitz.com/edit/measure?file=inner-element.js
I've discovered that a reliable way to get the rendered width and height of the inner-element is to access them in a window.setTimeout() callback registered in firstUpdated().
This is demonstrated here.
Whereas the LitElement doesn't always have access to its own rendered width and height when its' updated() or firstUpdated() is called, it does seem to have access to these values when the timeout callback is called.
I would feel more comfortable marking this answer as correct if I could articulate why this is the case, but empirically it is working.
Related
I am using NextJS and react-pdf/renderer and my tool creates a PDF and I'd like to display it with the PDFViewer component.
The Viewer loads but only takes up a small part of the screen. Whenever I change the 'width' and 'height' attribute with relative values (100%, 100vh), it won't take it. The only way to force it, is to put specific pixel values in it, but that defeats the purpose of being responsive to the screen size.
Sandbox that reproduces my issue: https://stackblitz.com/edit/nextjs-su5bi1?file=pages/index.js
Does anyone have an idea why this is happening?
Here is your screen with a red block of pixels of 150 pels high, note how it matches exactly your frame height.
Generally you ONLY set frame height in pixel units (The cross browser default minimum is 150?) you probably need somewhere to set a style defining the height as a different number of pixels.
see comment 2 in https://stackoverflow.com/a/73201090/10802527
In the Angular 11 project I need to change ng-circle-progress library CircleProgressComponent element size dynamically.
I have found out, that size of the element can be changed by putting width/height CSS properties on the child DOM element - svg. Problem is that svg doesn't have any id or class values, so even if I could somehow query the element, this would be not that easy and flexible as it should be.
Would be extremely nice to have a parameter in the CircleProgressComponent, that listens to outer variable changes and re-renders the element with a new size.
I had never used this library, so I've read their doc and thier demo page.
If I understand, they have the parameter that you want called radius
<circle-progress
[percent]="85"
[radius]="200" // the size you want
[outerStrokeWidth]="16"
[innerStrokeWidth]="8"
[outerStrokeColor]="'#78C000'"
[innerStrokeColor]="'#C7E596'"
[animation]="true"
[animationDuration]="300"
></circle-progress>
I have a QStackedWidget (QSW) with 2 child components, both are configured to expand to the size of their parents.
One of the child components (CC) resizes its content based on CC's size. These
calculated sizes are also used to determine the size of components which are always visible in a sibling of QSW. In order for these sizes to be always correct, CC needs to be resized even when it's not the active component in QSW.
What's the most straightforward way to accomplish this?
Edit: CC's sizePolicy is MinimumExpanding/MinimumExpanding, so the requirement is that CC's size is set to expand to the maximum size QSW allows it to, even when CC is not the active component.
This is a fine matter of whether or not the size hint works and what size policy is. In such cases the call of QWdiget::adjustSize is usually helping but to answer with confidence more context of your code is needed. Anyway, the docs say when it helps. I would trap the moment when the size is not correct and apply adjustSize. Mind that the scope where you apply adjustSize matters too.
Using a QStackedLayout with the StackAll stacking mode solves the issue. When the stacking mode is set to StackAll, all child widgets are showing, they just cover each other.
I am a little confused about the setActualSize method. It appears from what I've read, that if it is not called on a component by its parent, the component will not be rendered.
So it appears that setActualSize is a critical method that is directly bound to rendering the UIComponent. It also appears that the width and height properties of UIComponent override the functionality of the width and height properties of flash.display.DisplayObject, in that they are not directly bound to the rendering of the object but are virtual values that are mainly used by the getExplicitOrMeasured when the parent of the component calls the component's setActualSize method.
So the question are:
1) Why isn't the default behavior of every component to just call setActualSize(getExplicitOrMeasuredWidth(),getExplicitOrMeasuredHeight()) on itself?
2) I guess this question stems from the above question and the behavior as I understand it as described above: does setActualSize change the visibility of the component?
It appears that that the behavior is that a component is not rendered until setActualSize is called, but if it contains display object children itself (expected behavior as it can calculate measure on itself) and is added to the display list, the only reason why flash isn't rendering it, is because its not visible.
The answers to your questions are in the way the Flex component life cycle works, consider these two phases:
measurement:
The Flex framework will call the measure() method of your component. You can override this method to set a default and/or minimum size for your component.
Flex components first measure themselves to provide a default and/or minimum size suggestion to the layout/container classes. Flex does this from a bottom up approach, so that the lowest level objects are measured first. Thus when each parent object measures itself, the preferred sizes of it's child objects has been established.
rendering:
Later Flex calls the updateDisplayList() method of your component. You can override this to size/position your component's child objects. This is where setActualSize() is intended to be used: the parent calls setActualSize() on it's child objects, not on itself.
Note the method signature of updateDisplayList():
protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
Measurement was done from the bottom up. However, rendering is done from the top down. So at render time, updateDisplayList(unscaledWidth, unscaledHeight) gets executed on your component. Flex is telling your component the space it has been allotted to render itself, and your component must size/position it's child objects accordingly and/or do programtic drawing.
The sizes passed in to updateDisplayList() are based on various factors:
how/if you override the measure() method (measure is not called when
your component has a fixed width/height)
the types of sizing
parameters (fixed, percent, constraint) and layouts that you use
An old but good resource on this topic
setActualSize() is one of the crutial and most interesting methods in Flex layout process:
1) Notice that setActualSize() is an entry point for parent's layout to set the component size, and it has to be called by parent (container) almost exclusively!
This is because only the parent knows the amount of space available for each child (this method is being called after all children are measured and the container knows it's own given size).
(note: the example of not calling it by layout posted below)
This method exists because if parent would set 'width' and 'height' on children directly, they would immediately turn into fixed size children, and they won't be measured anymore.
Using this method, only the rendering size is being changed - not the (explicit) width and height but _width and _height - meaning if for some reason the container resizes again, the children will be resized by given rules (percentage of the parent, expanding to child component's children size etc.)
2) Yes, because if this method isn't called at all, the component has a (rendering) size of (0, 0), so this is the reason of it's invisibility (not setting 'visible' to false)! ^_^
Note that THERE HAS TO BE A LAYOUT (even a non attractive one) to trigger this method call. By 'non attractive' I consider the layout that isn't supposed to do anything smart, like CHANGE THE WIDTH AND HEIGHT of children at all (like absolute layout)!
Now, look at the PopUpManagerImpl's class addPopUp() method: there is an interesting case of calling setActualSize():
IUIComponent(window).setActualSize(
IUIComponent(window).getExplicitOrMeasuredWidth(),
IUIComponent(window).getExplicitOrMeasuredHeight());
Explanation: PopUpManager does stuff that layout should normally do, because it WANTS TO KNOW THE POPUP DIMENSIONS IMMEDIATELY, so it could center the popup on stage. It has no time to wait for the layout pass!
If you comment those 3 lines in the framework code, you'll see that popup is being centered with it's top left corner - just like it's size is (0, 0). Anyway, it is rendered with proper width and height because at rendering time the dimensions are known.
Hope this makes things a bit clearer...
Cheers! ^_^
Danko Kozar
I have a class which extends UIComponent and draws directly onto a Sprite contained within. Currently I'm (probably incorrectly) listening to the Event.RESIZE event and drawing the contents when the width and height are non-zero. The problem is that even though I've passed percentage widths to the instance tag, it doesn't appear to be resized along with other Flex components on the page, certainly the resize event isn't being fired at all.
I've hacked it for the moment by binding the width and height to a container which does resize, but how should I really be handling this?
Update :
It turns out I was setting the width and height somewhere in the redraw method (I have no recollection of why I did this!). I shall go hang my head in shame now...
I think you need to provide more information. I'm doing exactly the same, and it works smoothly for me. Perhaps the answer lies somewhere else: e.g. exactly what type of container do you use? Isn't it possible that the space gained/lost on resizing gets allocated to some other component within the cointainer? Try substituting your own component with an mx:Box with some colored background, and see if that resizes with the container.