We are currently building the UI for our next generation of products, which will allow to view and plan the schedules of thousands of employees simultaneously.
Our requirements is to display said schedules, one row per employee, with their scheduled activities in chronological order, similar to a gantt view in Microsoft Project. Usually, only 10 to 20 rows will be displayed at a time, although the user must be able to scroll smoothly through the table to see patterns throughout the whole solution. Statistical data tells us we want to be able to show 5,000 rows with an average of 100 activities per row. On top of that, we want to be able to view several of these tables in the same window.
Our first implementation uses Label nodes for activities as well as line and rectangle objects to separate the rows as well as days, weeks and months. In the worse case, we end up constructing at least 50,000 nodes although only 2,000 are displayed. Loading the canvas the first time takes about 75 seconds, which according to JProfiler is spent mostly processing the CSS, calculating the layouts and displaying the nodes to the user. After the initial load up times the scrolling is fluid, but adding a second canvas to the window makes the application unusable. We have already experimented with a pagination approach, which eliminated the initial load up time but made the scrolling choppy.
I have several questions:
- Do you think it is a good idea to have an JavaFX application with 50,000 to 300,000 nodes, even if only 2,000 to 10,000 nodes are displayed on screen?
- Should we use pagination and only create the nodes displayed on screen, even if it means choppy scrolling performance?
- Is there a way to disable CSS, anti-aliasing, or any other eye candy to test if the performance gets better?
- Would using a better graphics card improve performance? I currently have a 2.7GHz quad core CPU and a ATI Radeon HD3450
- Any other tips to improve performance? :)
You should use the ListView for this. It virtualizes each of the rows, so even if there are 50,000 rows or 5 million rows, the performance is snappy because it only creates enough nodes to represent the rows that are visible.
The ListView has a "cell factory" which will create a cell for each visible row in the ListView. These cells are reused as you scroll (cell has an update method on it which is called when it needs to repopulate or reconfigure itself based on it representing a new row). You can create your own cell factory which literally can produce a cell that looks however you want.
Thanks for the suggestion, I tried it out and I can create a ListView with 5000 rows, each with 100 buttons in an HBox. It doesn't take a long time to load, but the scrolling is a little slow. Profiling it shows most of the time is spent in JavaFx code (processing CSS, layouts, synchronize scene nodes), with just a portion spent creating the ListViewCells. I fear when we implement more complex controls in each of the cells the scrolling will become even slower.
Another concern I have is interacting with the controls inside each list view cell. It seems I can add context menus and click on the buttons that I added, which is a good thing. On the other hand, we have some advanced requirements like being able to drag and drop activities from one schedule to the other (persisting changes and updating the view), as well as being able to select activities from multiple schedules by dragging a rectangle over them. It would seem these features might be impossible or at least harder to implement by using a list view than by using a canvas.