Algorithm to determine if a component is fully visible in Flex? - apache-flex

Is there a built in way to determine if a component is fully visible in a Flex application (i.e. not offscreen one way or the other). If not how would I go about figurin it out?
I want to show or hide additional 'next' and 'previous' buttons if my primary 'next' and 'previous' buttons are off screen.
What event would be best to listen to to 'recalculate' ? stage.resize?
thanks!

here is a method for calculating if the component is within the bounds of the stage, it will not however tell you if the component is being hidden by another component, or if the component is being hidden because it is outside the bounds of another container.
public function isComponentWithinStage(c:UIComponent):Boolean {
var tl:Point = c.localToGlobal(new Point(0, 0));
var br:Point = c.localToGlobal(new Point(c.width, c.height));
//are we off the left or top of stage?
if ( tl.x < 0 || tl.y < 0 ) {
return false;
}
var stage:Stage = Application.application.stage;
//off the right or bottom of stage?
if ( br.x > stage.width || br.y > stage.height ) {
return false;
}
return true;
}

Could you give the specifics of the visible item and the container(s) it's in? Is it a matter of having to scroll some container to get to the buttons? Or is it a matter of someone has dragged a child window of a flexlib:MDICanvas partially off screen?
I think it's going to come down to if the x,y position of the component is beyond the width and height of its container, (and so on up through the parent containers until you reach your top level Application.)

Related

How to control scrolling of component in React?

I have 4 main components for my React portfolio site called Home, Portfolio, About, Contact. The components are linked in Navigation. If I click on those link, Component appears. But the problem is if I scroll the Portfolio page 50% and click on About. The About page stay automatically scrolled top by 50%. I don't want an automated scroll. Rather I want the component will start from top 0;
I have tried "css-snap-type" but it doesn't work.
How can I solve the problem?
you could solve this using a react component that will scroll the window up everytime you click on a different link.
checkout this documentation is pretty straight forward https://reactrouter.com/web/guides/scroll-restoration
If you are using gatsby it comes with and API called called shouldUpdateScroll you could implement it on the gatsby.browser.js
const transitionDelay= 500
exports.shouldUpdateScroll = ({
routerProps: { location }, //location
getSavedScrollPosition, //last position on the previous page
}) => {
if(location.action === 'PUSH'){
window.setTimeout(()=> window.scrollTo (0,0), transitionDelay)
}
else {
const savedPosition = getSavedScrollPosition(location)
window.setTimeout(
()=> window.scrollTo((savedPosition || [0,0])),
transitionDelay
)
}
return false
}
U need to set window.scrollTo(0, 0) when u click on link so it would start on top of page.

Scroll flex spark datagroup to maximum amount programmatically

I have a spark skinnable component which contains a datagroup with images. The datagroup is scrolled by hovering the mouse over it. Everything works fine except one thing: after I change the datagroup provider, I need to scroll down automatically. The problem is the images are not loaded immediately after I set the provider so (contentHeight - height) does not yet represent the actual maximum scrolling position. Is there an easy way of telling the datagroup to scroll down as its content loads? Because the workaround seems to be not so straightforward.
This is the code for scrolling(thumbnailStrip is my datagroup):
private function thumbnailStrip_mouseMoveHandler(evt:MouseEvent):void {
var fr:Number = (thumbnailStrip.contentHeight - thumbnailStrip.height) / thumbnailStrip.height;
var scroll:Number = fr * evt.stageY - fr * this.y;
var ms:Number = maxScroll();
if(scroll > ms) scroll = ms;
thumbnailStrip.verticalScrollPosition = scroll;
}
private function maxScroll():Number {
return thumbnailStrip.contentHeight - thumbnailStrip.height;
}
Thanks,
Calin
thumbnailStrip.layout.verticalScrollPosition += thumbnailStrip.layout.getVerticalScrollPositionDelta(NavigationUnit.END);
This may have to run a few times to get all the way to the bottom.It's supposed to return the difference between the current scroll position and the "end" of the scroll position. As things load, I'd just keep calling this in a "callLater".
btw, there's a bug for this: http://bugs.adobe.com/jira/browse/SDK-25740 not sure if it's fixed in 4.5, ugly workaround here: http://flexponential.com/2011/02/13/scrolling-to-the-bottom-of-a-spark-list/

Flex 4 spark List width resize issue

I've got a spark List with an item renderer. When I click on an element, the renderer becomes larger and when I click again, it becomes small again.
The problem is that list doesn't resize with the content. I've tried to dispatch an event from the renderer passing its content size and resize list in this way:
private function refreshList(event:ResultEvent):void
{
var size:Number = (event.result as Number) + 6;
if (size >= mylist.width)
{
consultingNumber++;
mylist.width = size;
}
else
{
consultingNumber--;
if (consultingNumber == 0)
mylist.width = size;
}
mylist.invalidateDisplayList();
}
consultingNumber is the number of 'opened' renderer.
It works quite well, but when all renderer is 'closed' an horizontal scrollbar appear.
Tracing list's width it result correct but the scrollbar is there even if I set horizontalScrollPolicy to off.
Try calling myList.invalidateSize() instead of myList.invalidateDisplayList();
Here is some more information about the flex component lifecycle which should get you on the right track:
http://weblog.mrinalwadhwa.com/2009/06/21/flex-4-component-lifecycle/
http://www.slideshare.net/rjowen/adobe-flex-component-lifecycle-presentation
Cheers

Canvas' verticalScrollPosition cannot be changed in Flex

I have a weird problem with verticalScrollPosition in Flex.
I have a content Canvas and a wrapper Canvas. The content is large (5000px X 5000px), the wrapper is 800px X 800px.
public var wrapper:Canvas = new Canvas();
public var content:Canvas = new Canvas();
wrapper.addChild(content);
application.addChild(wrapper);
I would like to set the wrapper's scrollbar position dynamically anytime. I can do it by calling its properties:
wrapper.verticalScrollPosition = A;
wrapper.horizontalScrollPosition = B;
This is working fine. But! If I set a default scrollbar position when the Canvas is complete:
wrapper.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void{
wrapper.verticalScrollPosition = DEFAULT_A;
wrapper.horizontalScrollPosition = DEFAULT_B;
});
I can't set the verticalScrollPosition anymore:
wrapper.verticalScrollPosition = C;
trace(wrapper.verticalScrollPosition); // Outputs: DEFAULT_A
So the problem only exist if I set a default position using 'FlexEvent.CREATION_COMPLETE'.
What am I doing wrong here?
Thanks in advance.
I've found a horrible workaround - I wait 1 microsecond to set the default state:
wrapper.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void{
setTimeout(
function():void{wrapper.verticalScrollPosition = DEFAULT_A;},
1
);
});
I think we can agree it's really ugly. How can I make it better?
I've found the problem. I attached the event listener to the child of the wrapper. When I added the listener to the wrapper itself it works.
So lesson I've learnt: always track the topmost ui element's events you have to work with.

Spark List scrolling by mouse position

<s:List xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
mouseOver="scroller_mouseOver(event)"
height="308" width="110">
As seen above, I have a Spark List with the MouseOver event:
protected function scroller_mouseOver(e:MouseEvent):void {
CursorManager.removeAllCursors(); // Remove all previous Cursors
if (mouseX > 24 && mouseX < 143) {
if (mouseY > 220) {
CursorManager.setCursor(downCursorSymbol); // Down Cursor
} else if (mouseY < 87) {
CursorManager.setCursor(upCursorSymbol); // Up Cursor
}
// Scroll as its Mouse Overed
this.addEventListener(Event.ENTER_FRAME, scrollViaY);
}
}
private function scrollViaY(e:Event):void {
if (mouseX > 24 && mouseX < 143) {
if (mouseY > 220) {
this.layout.verticalScrollPosition += (mouseY - 220)*0.5;
}
else if (mouseY < 87) {
this.layout.verticalScrollPosition += (mouseY -86)*0.5;
}
}
}
The following picture describes the area I would like to track hovering.
The Problem: When I hover the upper (red) part of the List (I would like to have the List scroll downward, the higher the mouse position is, the faster it should scroll). Similarly, If the mouse hovers over the bottom (red) part, the List scrolls upwards, and the lower the mouse is hovered, the faster the list would scroll. The current code does work - Though, the trace outs make it obvious that:
this.layout.verticalScrollPosition += (mouseY - 220)*0.5;
or
this.layout.verticalScrollPosition += (mouseY -86)*0.5;
...are giving jumping effects, is there a way to make these values change more linearly or smoother?
I created an AnimateProperty, but that works well only if I would like to scroll to a selectedIndex, In this case, I would like the scroller to keep scrolling linearly as the mouse is hovered to a particular red area, and increase in speed when I scroll to either extremity.
The Objective: While the mouse is over the Bottom (red part )of the List, the verticalScrollPosition scrolls faster as it gets farther than the center of the ticket list... yet there is jumping effect going on, I suppose due to the EnterFrame. the Same with Upper Part... the higher the cursor is, the faster the List should scroll.
I feel this is a common problem to Flash CSx developers.
I have implemented something similar, except it was a horizontal scrolling list, and also I used a scroll left/right buttons on the sides of the list, the mouse_over effect is triggered by the buttons, not the list (but this shouldn't be an impediment when adapting the code).
To do the actual scrolling, I used an animate effect which targeted the list's layout, and more specifically, the layout's horizontalScrollPosition. This it what the MXML code looks like:
<s:Animate id="scrollAnimation" target="{listLayout}">
<s:easer>
<s:Linear easeInFraction="0" easeOutFraction="0" />
</s:easer>
<s:SimpleMotionPath id="scrollMotionPath" property="horizontalScrollPosition" />
</s:Animate>
That easer is necessary because animate effect usually have 3 motion stages (acceleration, uniform motion and deceleration), so by default you would get a wavy scrolling motion.
I used RobotLeft for that project, so the view is mediated like this:
When the mediator is registered, add the scroll button listeners:
viewComponent.scrollLeft.addEventListener(MouseEvent.MOUSE_OVER, onScrollLeft);
viewComponent.scrollRight.addEventListener(MouseEvent.MOUSE_OVER, onScrollRight);
viewComponent.scrollLeft.addEventListener(MouseEvent.MOUSE_OUT, onScrollOut);
viewComponent.scrollRight.addEventListener(MouseEvent.MOUSE_OUT, onScrollOut);
We also need to add a listener so we can tell when the scrolling effect finished, because we might need to replay it:
viewComponent.scrollEffect.addEventListener(EffectEvent.EFFECT_END, onScrollEnd);
We can now implement the scrolling method. Since the view is mediated, we have access to the scroll effect, we can reference it here (and also the path). This what the method looks like:
private function scrollOnlineFriendsList(scrollBy:int):void
{
// Set the scrollBy value and play the scrolling effect
viewComponent.scrollMotionPath.valueBy = scrollBy;
viewComponent.scrollEffect.play();
// Store the scrollBy value in case the effect will need to be replayed,
// if the mouse over event is still over the scrolling button/area
this.scrollBy = scrollBy;
canKeepScrolling = true;
}
Finally, the handlers:
private function onScrollLeft(event:MouseEvent):void
{
scrollOnlineFriendsList(-33);
}
private function onScrollRight(event:MouseEvent):void
{
scrollOnlineFriendsList(33);
}
private function onScrollOut(event:MouseEvent):void
{
canKeepScrolling = false;
// If you would like the effect to continue playing
// until it finishes the current scrolling operation,
// once the mouse is no longer over a scroll button,
// just comment this line
viewComponent.scrollEffect.stop();
}
private function onScrollEnd(event:EffectEvent):void
{
// When the scroll effect has finished playing,
// if the mouse is still over the scroll button/area,
// replay the effect
if (canKeepScrolling)
scrollOnlineFriendsList(scrollBy);
}

Resources