Performance Improvements with 4.0 – The story of 90% performance gains

clock January 3, 2017 07:21 by author Flexicious

We recently completed an intense multi week consulting engagement where one of our largest customers invited us to help them improve performance of their application, one that had our Flexicious Ultimate DataGrid as the core of their product.

Their initial pain point was the amount of time it took for the grid to initialize, and then to scroll. We had made tremendous improvements in performance over the past few releases, but even with the last official release, they were seeing times > 10 seconds to scroll through a few hundred records (using the scroll bar, keeping the mouse down on the thumb track towards the bottom).

Here were the causes, and the work we did to alleviate them:

1)      Use of ITem Renderers : Most experienced Flex developers know that item renderers abuse can lead to performance problems. The default cell class used by our Flexicious Products (as well as the Adobe SDK datagrids) is a very lightweight class that inherits from the Flash Sprite object [FlexSprite]. When you use item renderers, you will see something like

<fx:Component>

<s:GridItemRenderer>
<s:Label color="blue" fontWeight="bold" text="{data.Name}"/>

<s:CheckBox/>                

</s:GridItemRenderer>

</fx:Component>

 

      In a vast majority of the cases, this will be fine – but – where this starts to cause a problem is this – imagine you have a grid with 20 columns – one that takes up a large amount of your screen (as many grids do) – so you are displaying lets say 50 rows on the screen – and you use item renderers like this on 5 columns – suddenly, you go from 1000 lightweight sprites to 1000 lightweight sprites + 250 VGroups+ 250 checkboxes+ 250 Labels. Now, the numbers aren’t so bad, until you really think about what a GridItemRenderer, or Label/CheckBox are. If you look at the inheritance hierarchy of a GridItemRenderer Inheritance Group Inheritance GroupBase Inheritance UIComponent Inheritance FlexSprite Inheritance, you can see that just using a GridItemRenderer adds the weight of UIComponent, GroupBase, Group on top of the cell. Even worse, is that with Flex 4 [See the Flex 4 version problems below] – because of Skinning, each component is actually 2 UIComponents – one for the actual component, and another UIComponent for the Skin. In fact, this can be so bad that simply adding ONE renderer to a large screen grid [Not just Flexicious Grid, even the SDK grids] will make it slightly sluggish, and the problem will worsen with more renderers.  To demonstrate this problem, we took a basic Spark DataGrid – added 20 columns to it, and scrolled – below are the results without any renderers-

And here are results with just 3 renderers:

 

You can see that just adding 3 out of 20 columns to have renderers makes the grid render 3 times slower!! And the renderers don’t even do anything

<columns:ExtendedGridColumn dataField="Name">

<columns:itemRenderer>

<fx:Component>

<s:GridItemRenderer>
<s:Label color="blue" fontWeight="bold" text="{data.Name}"/>

</s:GridItemRenderer>

</fx:Component>

</columns:itemRenderer>

</columns:ExtendedGridColumn >

<columns:ExtendedGridColumn dataField="Name">

<columns:itemRenderer>

<fx:Component>

<s:GridItemRenderer>                                 

<s:CheckBox/>                

</s:GridItemRenderer>

</fx:Component>

</columns:itemRenderer>

</columns:ExtendedGridColumn >

<columns:ExtendedGridColumn dataField="Name">

<columns:itemRenderer>

<fx:Component>

<s:GridItemRenderer>

<s:Label color="blue" fontWeight="bold" text="{data.Name}"/>

</s:GridItemRenderer>

</fx:Component>

</columns:itemRenderer>

</columns:ExtendedGridColumn>

 

            Remediation: Use Data Cell Renderer & Custom Background Draw Functions:

A little known feature of the product is the ability to define custom logic in the cell WITHOUT the use of itemRenderers – the dataCellRenderer. Conceptually, they are quite similar to itemRenderers – except itemRenderers sit INSIDE the cell, but dataCellRenderers ARE the cell. For use cases where you just want to change backgrounds, borders, colors of the text, or other attributes of the cell, all you have to do is to extend the lightweight base class FlexDataGridCell3 [or in the case of 4.0 you could use FDC5 but that’s for a later post]. What this does, is that it let use just use the TextField primitive that sits inside the cell. Below is an example of how this works, and a screenshot of the result – basically you have complete control over the cell without the use of item renderers. Use of this technique alone was responsible for 70 percent of the gains we were able to achieve.

 

 

2)    Use of Flexicious properties that automatically use item renderer equivalents – This turned out to be an interesting find. As you are aware, one of our strongest selling points is the massive number of features we ship with – but as you can imagine, every time you use a feature, the grid has to do more work. The more features you use, more work has to be done. But, what we found surprising was how often these features are used, and how heavy some of these can be in “perfect storm” type situations. In this case, the customer turned on the “truncateToFit” flag on all columns. When you do this, we basically swap out our lightweight cell, that does not have truncation support and use the Flex SDK text instead which has built in truncation support. We did not expect this flag to be used on every single column. [This has been changed in the 4.0 release – we have an optimized routine for this now]- The act of truncation in itself is expensive – the code has to measure text on basis of font sizes, figure out where to put the ellipsis, make adjustments for spaces, etc. Another culprit was the enableIcon property – the basic lightweight cell has no support for icons [Edit – this has also been changed for 4.0 – we have added basic icon support to the lightweight cell] – so we plug in the heavier UIComponent based cell that gets you a lot of these features. The problem is that you cannot “pick and choose” what you want from UIComponent – you have to either take the whole thing or nothing at all. So even if we need a small piece for styling/positioning, we would need to inherit from UIComponent with all of its weight – UIComponent also implements interfaces that the SDK forces us to implement for styling/rendering etc. Bottomline, all of these features turned on explained why even when the customer removed all of their renderers, the grid was still slow – the grid was still using the equivalent of renderers because of the features that were turned on. As of this writing unless you are using the upcoming 4.0 build, the following features prevent us from using the lightweight cells:

                                                              i.      truncateToFit [Fixed in 4.0]

                                                            ii.      selectable [Fixed in 4.0]

                                                          iii.      useHandCursor [Fixed in 4.0]

                                                          iv.      useUnderLine [Fixed in 4.0]

                                                            v.      wordWrap [Fixed in 4.0]

                                                          vi.      itemRenderer [C   onsider dataCellRenderer]

                                                        vii.      enableExpandCollapseIcon

                                                      viii.      enableIcon [Fixed in 4.0 – as long as icon is an embedded asset] 

Remediation:  to most of these requirements is to upgrade to 4.0, which adds these features to the lightweight cell in an optimized manner.

 

3)      As a corollary to #2, here are a few more properties that might affect performance, and what you can do to help:

a.       columnWidthMode = fitToContent. When you do this, the grid has to go through all the data, measure the text for each row, figure out which is the largest and set the columns width. If you are using an older version of our product, there was no limit on how many items we would go through. Later versions added columnWidthModeFitToContentSampleSize, so this should only be a problem if you have not upgraded in a while.

                                                              i.      Remediation: Upgrade to the latest version or do not use this property for larger datasets.

b.      filterComboBoxDataProviderBuildFromGrid – If you use multiselectcombobox or combobox as a filter control, the grid has a property called filterComboBoxBuildFromDataProvider. Majority of you set this to true. That is OK for smaller data sets. But for thousands of rows, the grid has to iterate through each row to identify unique values to display in the combobox.

                                                              i.      Remediation: Use filterComboBoxDataProvider to manually provide this list, preferably generate it on the server using a “select distinct”. If you are using server paging, you’d have to do this regardless because the grid wont have all the data to get the list.

c.       footerOperation: If you have a large number of numeric columns that each do their own footerOperation which is not a count – you should consider caching these calculations. footerLabelFunctions are called everytime filters are run – and there is an iteration loop for each column with a footer operation.

                                                              i.      Remediation: On dataProvider set and filter change, loop through the data provider once, performing all your calculations and then use the cached calculation result in footerLabelFunction.

d.      initialSortField: Sorting in Actionscript can be dreadfully slow for large datasets (especially case insensitive string sorting).

                                                              i.      Remediation: Instead of setting initialSortField, try to add the order by clause to your SQL statement on the server itself. Use Flash builder profiler to see how much time you are spending in Array.sort. 

 

4)      TLF (FTE) based text: This one surprised us. As most of you are aware, in Flex 4, Adobe introduced a new Text Layout Framework (TLF) based on the Flash Player Flash Text Engine (FTE). While this was a great addition for pixel perfect typography, it came at a cost in terms of performance. Here is a blog with some more issues with TLF - http://blog.gskinner.com/archives/2010/07/some_thoughts_o.html.

a.       Remediation - if you are using enableFTEDataRenderer, consider not using it, and just use embeddedFonts with mx.

5)      The version of the SDK – It is well known among the Flex community that Flex 4 components are much slower than Flex 3 components. Here are a few blog posts talking about this very issue : http://blogs.adobe.com/aharui/2011/04/migratory-foul-performance-problems-migrating-from-flex-3-x-to-flex-4-x.html & http://jackviers.blogspot.com/2011/03/flex-3-vs-flex-4a-performance.html Another issue, is that most Spark components do not implement IDataRenderer like most MX controls do – so you HAVE to wrap them inside a <MXDataGridItemRenderer> or <MXAdvancedDataGridItemRenderer> or <s:GridItemRenderer> before you can use them in our SDK extensions [Not Ultimate]. This in itself makes them twice as heavy – because the above three classes themselves inherit from Group. On top of that, Spark components each come with their own skin – so when you use a Button in Flex 4 based Flexicious Grid, you are now making it multiple times heavier than the same thing would have been in Flex 3..

a.       Remediation : Consider using dataCellRenderers, that still lets you use Flash player primitives for many real life business case scenarios.

6)      Not turning on enableEagerDraw – This is applicable for grids that wait for data. If you know what columns you are going to have (i.e. you are not building columns from the result of a server call) and you are not building a lot of other stuff along with the gird - you should set enableEagerDraw to true. By default, the grid will not do anything until the dataProvider is set. By setting columns, and setting enableEagerDraw to true, you are essentially breaking the grids’ initial render into 2 phases, the chrome build phase, and the data build phase. If you specify columns and set enableEagerDraw to true, the grid will draw the header, footer, filter, pager and then wait until you set the dataprovider to build the body. In this case, the grid was idling wasting time until the data came back and then doing all the work. We changed it so that it sent the server request, and while the server was processing, because of enableEagerDraw, the grid would draw the entire chrome and then build the body once the data came back.

a.       Remediation : For grids that wait for data and columns are known upfront, set enableEagerDraw to true. You can even set showSpinnerOnFilterPageSort to true and the grid will show a loading spinner while it waits for data.

7)      An older version of the Flexicious product: This particular customer was on 3.xx version of our product. 4.0 makes significant internal improvements, particularly in terms of caching information used to paint cells. It also adds more features to the lightweight class that can be turned on or off without having to inherit from UIComponent. In addition, 4.0 introduces the concept of “background sprites”. For grids that do not draw jagged cells, it uses a single sprite to draw the border and background for all cells.

a.       Remediation: Please upgrade to the latest 4.0 release.

 

There were certain factors that were specific to this application that made the problem worse:

1)      The grid took up over 90% of the applications screen real estate – nothing can be done about this, it’s just the way the application is laid out and the users wanted this.

2)      This was an internal application used by a team of folks who had large monitors with high resolution

3)      This application consumed live updates, and needed the grid to rebuild multiple times in response to rapid inserts and updates. We were able to avoid causing the rebuild and instead used the subscription information to internally manipulate the grid’s index.

4)      We isolated some memory leaks – specifically certain animations that were never destroyed even though were not visible – taking up valuable processing cycles per frame.

 

In conclusion,

Performance is one of those things that are so unique to each situation. While we can provide some general guidelines, it is incredibly difficult to optimize everything in every situation. As library/framework developers, we are always torn between two often competing aspects – convenience (ease of use) and performance. There is a famous quote in computer science – “Premature optimization is the root of all evil”. Optimizing performance is more of an art than a science. It involves careful analysis of what efforts will get you the most bang for your buck, it involves discussions with stakeholders as to what features are absolutely critical vs. a “nice to have”. After a certain number of iterations of improving performance, you hit the law of diminishing returns, where the effort involved does not warrant the miniscule gains, so this has to be a collaborative exercise to achieve the most optimal results. We routinely engage with customers in initiatives like this, and are able to help them get to a state where they are able to deliver value to the business in a way that is immediately noticeable. Please contact us to explore how we can help you as well!

 

Update: 4.0 is available now!!!

Most of the changes for 4.0 are focused on performance. To that end, the only major API change is ExtendedUIUtils.

ExtendedUIUtils.enableV4Optimizations

 

  • This flag is set to true - You can use this flag to turn off the optimizations in case they are interfering with anything. But please reach out to us with a small test case.
  • We have introduced a new flag, enableTFDataRenderer - this is currently in beta state. It does not work for nested grids and it does not work with row span and colspan. 
  • But for pure flat grids, it should increase performance even further.  
  • The following enhancements were made to FlexDataGridCell3 [which is the lightweight class introduced in 3.x]
    • Support added for truncateToFit
    • Support added for enableIcon
    • Support added for useHandCursor
    • Support added for wordWrap
    • Support added for selectable
    • Support added for useUnderline
    • If you had any of the above flags set to true, upgrading to 4.0 should get you a noticable increase in performance.
  • Bug Fix - cache hit misses for false values has been fixed, improving performance
  • Bug Fix - column drag drop interfering with Drag Drop Grouping issue fixed
  • Bug Fix - gotoItem did not work if you go to last row
  • Responsive behavior added 
  • Bug Fix: The datagrid is 1px bigger than the height specified by the component attribute . 
  • Bug Fix: in the ExtendedAdvancedDataGrid where you have locked columns in the grid and type into a textinput filter, the filter loses focus after the filter has been applied, had been fixed. 
  • Fix for building TransposedColumnItemRenderer in Flex 3.x
  • Fixed memory leak related to cleaning up open items when data provider changes
  • Changed signature of setEditedItemPosition to make it easier
  • Fixed issue with drag and drop enabled grids having scrolling issues with column resizing
  • Changes so that responsive behavior only kicks in once per resize
  • Added documentation for responsive behaviors/ResponsiveBehavior.js
  • Better text rendering for alive pdf printer for multiline text.
  • Updated build scripts to include new files for Responsive code
  • Some changes for native pdf/AlivePdfPrinter.as
  • Bug Fix: We have a column that can have the values as BLANK (empty string ” “), CAT, and DOG. When I select to filter on BLANK fields, only my column values that contain “ “ will filter. This part works just fine. I’m not sure why, but when I load the preference string into the grid, it does not display my saved filter to be BLANK like it should. It defaults to ALL being selected (BLANK, CAT, DOG).
  • Bug Fix: Custom filter render, com.mb.filter.DynamicFilterControl. The filter works but when we save the preference and the reapply it does not work.
  • Added support for enableBackground (for grids that dont paint a background) - set this to false if you dont have a background.
  • Bug Fix : We have server side persisted preferences.  When I go from a grouped saved preference to a non-grouped filtered preference I loose all data.This only happens in a scenario of grouped to filtered.  If I go from a grouped to sorted or some other simple preference it works correctly.
  • Bug Fix: We have a column that can have the values as BLANK (empty string ” “), CAT, and DOG. when I load the preference string into the grid, it does not display my saved filter to be BLANK like it should. 
  • Bug Fix: Fixed issue where Print and PDF of grids with horizontal scroll policy auto but columns not wide enough causing last column to stretch cause weird appearance in the print view.
  • Bug Fix: Description:  We are no longer able to move columns whenever the Drag Bar Grouping Feature is enabled on the report.
  • Bug Fix: When we upgraded to the newest Flexicious, we no longer had the ability to persist the numeric filters when grouping preferences are set.
  • Bug Fix: Added column glyph when you are dragging columns

            Following new properties were added:

            /**

             * Flag used add column group separator line - after the last visible column of each column group a new line will be drawn to demarcate the end of that column group

             */ 

            public var enableColumnGroupSeparators:Boolean = true;

           

            /**

             * Flag used to turn on right click row selection.

             */        

            public var enableRightClickSelectRow:Boolean=true;

            /**

             * When you scroll, the grid will destroy the current item editor. If you set this to false, it wont.

             */        

 

            public var destroyEditorOnMouseDownOnGrid:Boolean=true;

 

 

 



Another selectedKeyField Question

clock May 27, 2016 01:11 by author Flexicious

Had an interesting issue today

 

Question:

I'm been trying to get the reopen items feature to work  and I must have a basic misunderstanding. On the grid, I  have the following:


 

clearOpenItemsOnDataProviderChange = "false"
clearSelectionOnDataProviderChange = "false"
selectedKeyField="divisionUniqueKeyForSorts" 

As you can see from this first screenshot, the division root is the only item that has this unique key 
and, in fact, it does remember the open items when I refresh the dataprovider, just as I would like. However, whenever I try to select a single line which is needed in my app, it selects all the children.

-> Answer,
The fundamental issue here is that the requierment of a selectedKeyField - that it needs to be globally unique (across all children AND parents) is not being met. The selectedKeyField makes it easy for us to recognize "business equality" vs "object equality". From the docs:
"The selectedKeyField is a property on the object that identifies the object uniquely. Similar to a surrogate key, or a business key, as long as it uniquely identifies the object. When this property is set, the selected keys returns the ID values of the objects that were selected. When a row is selected in the grid, we store the selectedKeyField property of the selected object in this array collection. This allows for multiple pages of data that comes down from the server and not maintained in memory to still keep track of the ids that were selected on other pages."

This SAME concept is used to track which items stay open. In other words, if object with ID 1 is refreshed multiple times, even if it is a different object coming back from the server, it will stay open, because you have set selectedKeyField. 

But in this case, the requierment of a selectedKeyField - that it needs to be globally unique (across all children AND parents) is not being met. So the only option is to either introduce such a field that exists across all objects, (parents and children) and ensure iti is globally unique, or set
clearOpenItemsOnDataProviderChange = "true"
clearSelectionOnDataProviderChange = "true"
selectedKeyField="" 


And manually track openItems and selectedObjects across refreshes.





Native PDF Generation for MX DataGrid, AdvancedDataGrid and Spark DataGrid

clock February 22, 2016 07:24 by author Flexicious

For those of you who recently upgraded to our latest 3.3 release, one of the biggest enhancements was support for Native PDF generation. AT the time of release for 3.3 we had only implemented this for our Ultimate DataGrid. However, we are aware that a significant number of you are also using our Classic product - our Extended DataGRid, AdvancedDataGrid and Spark DataGrid. - and to accomodate your needs, we have implemented the same support for those three products. 

You do need a new build get this support - so please request a build even if you have 3.3. 

Below is the complete sample project:

PDF Test.zip (290.27 kb)



Native PDF Generation From Flex DataGrid with images

clock February 16, 2016 00:18 by author Flexicious

For those of you who recently upgraded to our latest 3.3 release, one of the biggest requests had been support for custom item renderers with images in the PDF generation routine.  The older PDF mechanism basically grabs screen shots of the grid and adds to the page. This works great and most scenarios but the biggest drawback of this mechanism is the quality of the PDF. This is because a screenshot is at the end of the day a bitmap image. It is not a vector and it doesn't scale. So in 3.3 we changed that and added support for generating PDF documents using the grids rendering mechanism - however, there was a catch - we could only render text. This made things like images not render in generated pdf documents. However, since a number of you asked for this, we added support for images as well.

Below is a sample that demonstrates this functionality. It was not very easy to accomplish this - but we always appreciate a challenge!

Quick Note : The developer who made this sample is a cricket fanatic, a game which some of you might be familiar with :-) For those of you who arent, its a game that originated in England but is played the word over very similar to baseball.  

Enjoy!

Sample code: Cricket.zip (192.18 kb)

Generated PDF: Test0.6235653976909816.pdf (135.43 kb) 

 



Maintain open items in Flex DataGrid

clock February 15, 2016 17:10 by author Flexicious

Question : "Could you point me to a tutorial or sample app that stores the open items on NestedDataGrid, then after updating of the dataProvider, opens up the same items on the displayed datagrid."

Answer :  

 

Have you set a selectedKeyField? Here is a key piece of information: The grid stores the list of open items in grid.openItems. When you replace the dataprovider, the grid will clear out the open items array, unless you set clearOpenItemsOnDataProviderChange to false. But even if you set it to false, for the grid to keep track of what is truly open, it needs to know which “object” in your dataprovider is open. Now, for this the default test is object equality. So, if you change the dataprovider, object equality test will fail, and items will still be closed (because the same business object in the new dataprovider may not match object equality test for the version of it in the old dataprovider – setting the selectedKeyField helps us bypass this problem by identifying ‘open’ and ‘selected’ records post a dataprovider refresh. please read this link to understand : http://htmltreegrid.com/newdocs/html/Flexicious%20HTMLTreeGrid.html?SelectedKeyField.html ). So, there are 2 options

 

1)       Set clearOpenItemsOnDataProviderChange to true (default) and set grid.openItems manually after you set the dataprovider

2)       Set clearOpenItemsOnDataProviderChange to false, and let grid maintain openItems, but set the selectedKeyField when you do this so the grid knows which object in the new dataprovider are equal to the ones from the old.

 

 

Attached is a sample

 

SelectionOptions.mxml (4.57 kb)



Quick Fix for AdvancedDataGrid not maintaining widths when data provider refresh

clock January 31, 2016 03:30 by author Flexicious

Recently, we addressed an issue for a customer:

Issue : One thing I have found is that (in some cases) if I set the dataprovider for the datagrid after the datagrid is initially created, the widths are correctly set, but if I set the dataprovider in the mxml code for the grid and bind an array collection to it, the column width settings are not respected.    

 

Another issue we have is that when we change the dataprovider content for the grid, the columns resize themselves after refreshing the dataprovider.  An example project showing this is attached.  In this project, the dataprovider contains a single record and is loaded when the datagrid loads.  When hitting the 'Refresh Data Provider' button at the bottom of the app, I clear the dataprovider, refresh the dataprovider, add the record back to the dataprovider, and then refresh the dataprovider again.  As you can see, the column widths spontaneously resize themselves after the refresh.  Can you please advise as to how we can better control our column widths under these conditions.

Solution:

The problem here is that there are two rounds of code that run to calculate the widths of columns. The first round is the default SDK code - we need it to run to figure out the initial set of column widths. The second pass is our code, which basically adds support for things that are covered using our columnWidthMode. Column Width Modes are an very nuanced topic, as you can observe from this documentation : http://www.flexicious.com/resources/docs29/com/flexicious/nestedtreedatagrid/FlexDataGridColumn.html#columnWidthMode. But irrespective of that - the issue is that once they are calculated, the input for the next round of calculations is not the same as before. So what we have done, is added a property - autoApplyColumnWidths - this will cause the column widths to calculate only once, and that too when you call it. This way, we dont override the initially calculated column widths. 

 

<grids:ExtendedAdvancedDataGrid  id="dgCfgList" 

dataProvider="{devConfigListArr}"

autoApplyColumnWidths="false"

 

And then you manually call applyColumnWidths after you set the data provider - make sure you call validateNow prior to this, so the first pass of the width calculation executes.

devConfigListArr.refresh();

dgCfgList.validateNow();

dgCfgList.setColumnWidthsUsingWidthMode();




Flexicious 3.3 Released

clock January 1, 2016 01:44 by author Flexicious

As we close out a terrific 2015 and ring in 2016, we have been hard at work here at Flexicious wrapping up our newest release 3.3. As with the past couple releases, this one is huge as well, and the full scope of this release has been broken into almost half a dozen individual blog posts that we've been publishing over the past few weeks. As you consume all of this, please keep this in mind - we are and will always be committed to Flex, and our Flex products. We will continue to invest and improve on them - but we ask your help. We are probably among the last few companies still actively developing Flex products. While we've diversified from a technology perspective Flex has always been our favourite stack -its where we feel most at home. Fortunately, we have numerous customers who are just as passionate about the techonology as we are, and have been supporting us via regular renewals. WE thank you and hope we live up to your expectations. For those of you who have not renewed but are still using Flex, please, consider renewing. This gives us the motivation we need to continue to improve and add new features.    

  • Bug Fixes

    • We have a column that can have the values as BLANK (empty string ” “), CAT, and DOG. When I select to filter on BLANK fields, only my column values that contain “ “ will filter, but when I load the preference string into the grid, it does not display my saved filter to be BLANK like it should. It defaults to ALL being selected (BLANK, CAT, DOG).

    • If we have a custom filter render, DynamicFilterControl. The filter works but when we save the preference and the reapply it does not work.

    • Fix for source code could not be compiled with Flex 3.x

    • We have server side persisted preferences.  When I go from a grouped saved preference to a non-grouped filtered preference I loose all data.

    • This only happens in a scenario of grouped to filtered.  If I go from a grouped to sorted or some other simple preference it works correctly.

    • Fixed issue where Print and PDF of grids with horizontal scroll policy auto but columns not wide enough causing last column to stretch cause weird appearance in the print view

    • Added Support for PDF and Export of Grouping Data

    • Added support for column headers to include the full column group text

    • Added support for export and print views to include full column group text.

    • We are no longer able to move columns whenever the Drag Bar Grouping Feature is enabled on the report.

    • When we upgraded to the newest Flexicious, we no longer had the ability to persist the numeric filters when grouping preferences are set.

    • Added column glyph when you are dragging columns (So the user can drag and drop to rearrange columns as well as do the grouping using the Drag Drop grouping)

    • Fixes for drag drop grouping with legacy preferences.

    • If you have an ExtendedAdvancedDataGrid with text input filters, if you also have lockedColumns > 0, then when you type into one of the text input filters, the filter will lose focus after filtering.

    • Fix for textColor - I want my text color in my renderer to stay the color black but it still goes grey even when I set the disabledColor property on the column.  Without the renderer, it works great.

    • Bug fix for label size on treemap/TreeMapPainter.as

    • Fix for XML Exporter not writing out footer.

    • Scroll H-Scroll bar to extreme right. Try to drag any column to the extreme right of the grid. Now try to drag another column, user unable to drag any column if user tries to shift column after last column

    • Bug Fix for fix for LineChartPainter - drawing from 0,0 does not work

    • Fix for able to enter characters like '?' and '*' in the numeric input.

    • Fix for copy selected objects with dynamic levels not working, and checkbox selection with enableStickControlKeySelection false.

  • Enhancements

    • Added support for grid wide column spanning cells. If you return -1 indicates the cell should occupy just its own spot. Any number greater than one would position the cell so it covers the width of that number of cells

    • Added selectedObjectsAtAllLevels - [Read Only] A list of selected objects from the data provider. This is the sdk equivalent of selectedItems. We do not have selectedItems, but selectedObjects will almost always be the same as selectedItems. The only exception is when you use server side paging. In this case, selectedObjects will contain all the items selected, on all pages. When a row is selected in the grid, we store the the selected object in the selectedObects array collection. This allows for multiple pages of data that comes down from the server and not maintained in memory to still keep track of the objects that were selected on other pages. Please note, for hierarchical grids, each level has its own collection of selected keys. The grid.selectedObjects returns the selectedKeys at the top level. To access the selected keys at a lower level, you may navigate to that level using grid.columnLevel.nextLevel...nextLevel.selectedKeys

    • Added support for enableFTERenderer

    • Added support for enableBackground (for grids that don’t paint a background)

    • Made FDGC4 work (for memory)

    • Added Performance improvement - enableStyleCache - http://blog.flexicious.com/post/Upcoming-33-release-Performance-Improvements.aspx

    • Support for clearing grouping criteria – clearGrouping() added to DragDropGroupingBehavior.as

    • Added cellEditEnterKeyTabsToNextEditableCell : By default, the enter key will look for a cell below the current cell. As opposed to the tab key which will navigate to cells starting to the right. Setting this flag to true will cause the user to navigate to the next editable cell (just like the tab key)

    • Changes so that responsive behavior only kicks in once per resize

    • Added documentation for responsive behaviors/ResponsiveBehavior.js

    • Better text rendering for alive pdf printer for multiline text.

    • Updated build scripts to include new files for Responsive code

    • Support for tree map label font size in TreeMap.

    • Added labelFontSizeFunction to TreeMapSeries : Function that determines the label font size. If null, the chart will calculate its own Should take a label Object, a String object, and return a number.

    • Added support for Line Chart Painters to draw broken lines: drawBrokenLines added to LineSeries : When there is a NAN value encountered while drawing a series, we currently just draw a broken line. You can set this flag to false and it will draw through the points to the next real point.

    • All Charts – Support for skipping drawing labels when there is no text returned – One of the biggest things slowing down charts is the issue of drawing a LOT of data points. Each data point requires potentially a label (UIComponent) created – this is especially true for Axes. What this changes does is that via the labelFunction, if you return blank, we don’t draw the label associated with the data point (for an axis, we draw the tick, but not the label on the tick). This allows you to render a lot more data points on the chart with fewer labels.

    • Added allowNoneSelection to MultiSelectComboBox - By default, the combobox does not allow you to select none items. Since it is usually used in search scenarios, you have to select something to search on. However, in cases where you are using the MSCB in non-standard scenarios, setting this flag to true will let the OK button be enabled.




Upcoming 3.3 release - Custom Stylesheets for HTML and Word Exports

clock January 1, 2016 00:48 by author Flexicious

A minor new enhancements to the upcoming 3.3 release is the support for addition of styling information for Word and HTML Exports. You can now add support for backgrounds, borders, fonts, colors, etc to the generated file. The style information is contained in the constants class, and you can modify this:

Below is the default, which you can customize as you see fit. 

 

Constants.HTML_EXPORT_CSS= "<style>"+
   
"table {font-family: Arial, Verdana, sans-serif;border-collapse: collapse; border-spacing: 0; }       "+
   
"td {border: 1px solid #CCC; text-align: center;width: 10em;padding: 1em;}    "+
   
"th {border: 1px solid #CCC; text-align: center;padding: 1em;background-color: #DFDFDF;}"+
   
"tr {height: 1em;}"+
   
"table tr.even {background-color: #F1F1F1;}"+
   
"table tr.footer {border: 1px solid #CCC; text-align: center;padding: 1em;background-color: #DFDFDF;}"+
    
"table tr.odd {background-color:#fefefe;}</style>";

Constants.WORD_EXPORT_CSS= "<style>"+
   
"table {font-family: Arial, Verdana, sans-serif;border-collapse: collapse; border-spacing: 0; }       "+
   
"td {border: 1px solid #CCC; text-align: center;width: 10em;padding: 1em;}    "+
   
"th {border: 1px solid #CCC; text-align: center;padding: 1em;background-color: #DFDFDF;}"+
   
"tr {height: 1em;}"+
   
"table tr.even {background-color: #F1F1F1;}"+
   
"table tr.footer {border: 1px solid #CCC; text-align: center;padding: 1em;background-color: #DFDFDF;}"+
   
"table tr.odd {background-color:#fefefe;}</style>";




Upcoming 3.3 release - Responsive DataGrids

clock December 24, 2015 00:28 by author Flexicious

Readers of our blog know that the past few weeks have seen tremendous development activity on the product. The upcoming 3.3 release adds a highly requested feature : Support for Responsive DataGrid (Responsive Datatables)

Displaying data across various different screen sizes and resolutions has been a challenge few have been able to solve effectively. There are many solutions online, but we have gone a step further by taking Flexicious Ultimate, which is arguably among the most powerful DataGrid component for Flex applications, and added support for responsive rendering. We wanted to give you flexibility over how you want the grid to behave, so we have implemented 3 (THREE!!) different responsive modes:

1.   API to show or hide the scroll bar on basis of the screen width. Below a certain pre-configured screen width, a scroll appears, and allows the user to scroll through all the columns. Above this screen width, there is no scrollbar.

2.     An API for a priority model, where each column can be assigned a priority and the columns appear or be hidden on basis of screen width.

3.     A new column type, TransposedColumn added to accommodate smaller screens, below a certain pre-configured width, all the columns in the grid are replaced by the Transposed Column which contains, within a single cell, all the information that was held in the
previous cells in a transposed manner.

That said, lets talk about each of these modes and what they mean:

1)                      The Scrollbar mode - ResponsiveBehavior.SCROLL_BAR_  : This mode basically says, below a certain threshold (scrollBarWidthTreshhold – default 1000px), the grid will display no scrollbar. But above this width, a scrollbar is shown. This is distinct from the horizontalScrollPolicy=auto. As some of you may know, column widths are a highly nuanced topic. The widths work very differently when horizontal scrollbar exists vs not [You set this via the horizontalScrollPolicy on the grid]. There is also the additional complexity of the columnWidthMode attribute on each column that makes this further nuanced. The one thing to keep in mind is that the responsive mode does not really ‘change’ the behaviors associated with horizontal scroll policy. It merely flips the horizontal scroll policy to on or off on basis of the width of the grid in comparison to the scrollBarWidthThreshold. The behavior of individual columns in this mode still respects the original behavior. There is a lot more information about how each column is sized in each horizontal scroll policy mode, which is clarified here : http://www.flexicious.com/resources/docs29/com/flexicious/nestedtreedatagrid/FlexDataGridColumn.html#columnWidthMode

2)                      The Priority mode - ResponsiveBehavior.COLUMN_PRIORITY_MODE : This mode will show or hide columns on basis of the priority associated with them, and the threshold set on the behavior. There are 5 priority modes. Below are the settings for each priority modes – Please note, these are default values and can be configured to whatever values you like.

/**

*  The width below which columns with priority 1 are not visible.

* @type {number}

*/

this.columnPriority1WidthTreshold = 1120;

/**

*  The width below which columns with priority 2 are not visible.

* @type {number}

*/

this.columnPriority2WidthTreshold = 960;

/**

*  The width below which columns with priority 3 are not visible.

* @type {number}

*/

this.columnPriority3WidthTreshold = 800;

/**

*  The width below which columns with priority 4 are not visible.

* @type {number}

*/

this.columnPriority4WidthTreshold = 640;

/**

*  The width below which columns with priority 5 are not visible.

* @type {number}

*/

this.columnPriority5WidthTreshold = 480;

3)                      The Transposition mode - ResponsiveBehavior.TRANSPOSED_COLUMN_MODE : Similar to the scrollbar mode, this mode will show or hide a transposed column on basis of the current width of the grid in comparison to the value defined for the transposedColumnTreshold (default 450). Below this threshold value, all the columns disappear, and a single column appears which is a transposed version of all the columns in the grid. The advantage of this mode is that all the information rendered in all columns is visible. This mode currently only works with flat data (not hierarchical data). The biggest disadvantage obviously is that you loose the sorting capability across all columns, but you can enable the muticolumn sort and that allows you to modify the sort using the sort popup.

As with any newly added feature, we are hoping to make this seamlessly integrate across all other features (for example, the print/export currently does not work with Transposed columns). We are actually looking for feedback on how this will work in general, so please feel free to share your thoughts

 

Wondering what this looks like?.

1) Here is the default grid (notice the large number of columns)


 

2) Here is the same grid, smaller width, with scrollbar responsive mode (notice the scrollbar at the bottom, which was not there prior to the grid being resized)

3) Here is the same grid, with the priority responsive mode (notice not all columns are visible) the ones with lower priority are hidden.

4) Finally, Here is the same grid, with the transposition responsive mode.


As may have been obvious from the slew of posts about our upcoming features, we have been hard at work trying to make the product even better, if you have not renewed your subscription, show us your support and now would be the time to do it!

 

Finally, below is the sample code used to implement this. (You will need the latest 3.3 release - we have a pre-release available if you want to take it for a spin)

Responsive.zip (274.47 kb)



Upcoming 3.3 release - Pure Native PDF!

clock December 21, 2015 19:54 by author Flexicious

One of the most exciting features to be added to 3.3 and one that we think a lot of you are going to be able to use immediately is the support for native PDF. As most of you are aware the current PDF mechanism basically grabs screen shots of the grid and adds to the page. This works great and most scenarios but the biggest drawback of this mechanism is the quality of the PDF. This is because a screenshot is at the end of the day a bitmap image. It is not a vector and it doesn't scale.

In this release we're basically changing how the AlivePDFPrinter works. Conceptually if you think about our print mechanism what we do is we basically just render the grid to either the printer or the PDF. The grid already takes care of the complex mechanism of figuring out the page size, identifying which rows belong to which page how much data can be fit within a single page and all of that good stuff. So far all we did is let the grid take care of the rendering mechanism and then capture the screen shot of the grid. In this release what we're doing is extending the printer to instead of capturing the screenshot of the grid we basically take the rendering information from the grid and then use that to render native PDF objects.

From design standpoint our PDF pages basically include a report header, page header, the grid area, the page footer and the report footer.  The report header and a report footer are on the first page and the last page respectively. The page header and page footers exists on all pages.  Report headers footers and page headers footers are always a fixed size. You define the sizes when you define these renderers.  Once the sizes for these fixed areas is allocated the grid then takes up the remaining size and on basis of the size of the grid on each page we have to identify which cells in which rows exist on each page. We do all of these calculations up front and then use that information to build the preview. What we can do now with this release is use the same information to render out natural PDF using the API provided by the PDF library which is our case, Alive PDF.

Now that you understand technically what the change means let's talk about what it means to you from a code change perspective. the most obvious change to  enable this behavior is to basically said a flag on the PDF options object.

/**

        * Flag added in 3.3 to enable passing an image to the pdf printer as opposed to the

        * actual display object. Defaults to true, because currently we just add a snapshot of the

        * current view to the PDF page. If this flag is set to false, we will pass the actual display object

    * (and not the image snapshot) to the pdf printer. The pdf printer then has to be smart enough to

        * parse through the Display Object, and call the appropriate APIs on the pdf library to convert

        * the Display Object to PDF version of it.

        * */   

        public var pdfUseScreenShot:Boolean=true;



And then set this flag to false:

protected function vbox1_creationCompleteHandler(event:FlexEvent):void

              {

                    grid.pdfOptions.pdfUseScreenShot = false;

                   

              }

When you set this flag to false what it tells the grid  is that instead of capturing the screenshot of the grid what we want is to capture the information from the page itself.  All of this work is done in the printer.


The next thing you have to do is to use the updated version of the printer you can download this here:

 

The final caveat to keep in mind is that there are two modes for the printer - there's a wrap mode and the no wrap mode.  On the screen if the text with the the cell is larger than the area of the cell in other words if there's not enough space to render the entire content of the cell we usually just cut off the part of the cell text that cannot fit within the area. We can replicate that same behavior in the printer or we can try to fit as much as possible by wrapping the text.  The advantage of not wrapping is that the PDF looks cleaner but the disadvantage is that the information is cut off.  On the other hand if you set the wrap mode to true we'll be able to fit more information but it looks a little cramped. Below are sample outputs - Before, After with wrap, and After No Wrap.

You can flip the wrap setting using the following line of code in AlivePDFPrinter:

           private var pdfWrapText:Boolean=false;

 

To Summarize:

  1. This release includes pure native pdf exports as opposed to the older screenshot based pdf

  2. Now PDF’s can be scaled, they are no longer bitmap images

  3. You can select and copy text from generated PDF files

  4. PDFPrinter supports wrap and no wrap modes (example outputs follow)

  5. To use, set the flag on pdfOptions, and use the new AlivePDF Printer

  6. If you have customized report/page header/footer, modify the AlivePDFPrinter to account for that.

  7. Help us improve this feature by providing feedback!


 

 

 

Enjoy!

Before / After documents : 

Older Screenshot based PDF.pdf (108.29 kb) (Flexicious 3.2 or earlier)

Pure Native PDF With Wrap.pdf (498.74 kb) (Flexicious 3.3)

Pure Native PDF No Wrap.pdf (491.82 kb) (Flexicious 3.3)

Alive PDF Printer Class : AlivePdfPrinter.as (18.18 kb)

Sample Project: OnePager.zip (172.25 kb)