Skip to content
This repository has been archived by the owner on Jul 29, 2019. It is now read-only.

Improve Item redraw and initial draw performance #3475

Merged
merged 11 commits into from
Sep 29, 2017

Conversation

yotamberk
Copy link
Contributor

Based on the work done in #3409, I've improved the performance of the timeline redraw time by 2-5 times faster! Initial draw has been reduced to less than 1 seconds for 1,000 items across 10 groups.
default

This PR includes parallel redrawing of items in the same group avoiding "read,write,read,write" reflow/repaint delays of the browser, reducing it to a single repaint per all items' action in redrawing queue.

Further work needs to been done for:

  • parallel redrawing of items across different groups.
  • move the redraw queue of each item type to a general redraw function under the Item.js file (since the redraw function is identical to all.)
  • Improve even more unneeded repaints occurring in initial drawing of the timeline and redraws called in events preceding initial draw.

@yotamberk yotamberk requested a review from mojoaxel September 22, 2017 13:45
@yotamberk yotamberk changed the title Improve Item redraw and initial draw performance WIP: Improve Item redraw and initial draw performance Sep 22, 2017
@yotamberk yotamberk changed the title WIP: Improve Item redraw and initial draw performance Improve Item redraw and initial draw performance Sep 23, 2017
@mojoaxel mojoaxel removed their request for review September 26, 2017 14:40
Copy link
Contributor

@wimrijnders wimrijnders left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is enough for a first round.

Actually, as far as I can tell the fix is good. Just needs cleanup. Don't let the number of comments despair you.

var groupCount = 20;
var itemCount = 400;

function genName(length) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect a short description around here, about what this example is about.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous comment is misplaced; it should have been in the HTML section.

// create a data set with groups
var groups = new vis.DataSet();
for (var g = 0; g < groupCount; g++) {
groups.add({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indent, we're sort of standardized on two spaces, can we keep it like that? Comment applies to whole file.

@@ -0,0 +1,78 @@
<!DOCTYPE HTML>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this example, works fine. So I won't put too much effort in trying to understand the details.

var container = document.getElementById('visualization');
var options = {
width: '100%',
//autoResize: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why this commented stuff is here? If so, add a clarification. If not, remove.

//groupOrder: 'content',
};

var timeline = new vis.Timeline(container);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a stress-test, as the name implies, how about adding timing here? To understand the gain.

this.dom.box.className = this.baseClassName + className;
}
}
BackgroundItem.prototype._getDomComponentsSizes = function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put empty lines between methods. Please review the whole PR for this.

// recalculate size
this.props.content.width = this.dom.content.offsetWidth;
this.height = 0; // set height zero, so this item will be ignored when stacking items
BackgroundItem.prototype._repaintDomAdditionals = function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the empty method needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because all the other items contain 6 actions, I wanted to insure that all items have the same number of actions (and that the same function type is done in parallel - this is a preparation to making the redraw queue for all the items defined in the Item.js prototype) + it's a space keeper for future implementations of dom additionals to background items (I've been planning to add)


(function() {
if (this.dirty) {
sizes = this._getDomComponentsSizes.bind(this)();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? Why the bind here? Isn't it bound already (after function def)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because _getDomComponentsSizes needs the this

* @return {boolean} the redraw queue if returnQueue=true
*/
RangeItem.prototype.redraw = function(returnQueue) {
var sizes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

; - If you had DRY'd this before, you'd need to change it only once.

* @param {boolean} [returnQueue=false] return the queue
* @return {boolean} the redraw queue if returnQueue=true
*/
RangeItem.prototype.redraw = function(returnQueue) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strike four: Image Samuel L. Jackson holding a gun against your head and what he would say about DRY-ing this.

// update dirty DOM. An item is marked dirty when:
// - the item is not yet rendered
// - the item's data is changed
// - the item is selected/deselected
Copy link
Contributor

@wimrijnders wimrijnders Sep 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's actually not what I meant. I meant a comment block like at line 132. Oh well, at least you DRY'd it.
Edit: No, you didn't. You just moved the blocks. But it's in one of the duplicated parts so I guess it will work out in the end.

@wimrijnders
Copy link
Contributor

As a reviewer, I'm not too happy with the resolution of this issue. I really do think that 4xduplication is a bug.

But I do realize that you're anxious to get this in.....and I already said that the fix is good.
Still, I don't want you to get off that lightly. I'm going to make an issue for you for the DRY'ing, so you don't forget.

@yotamberk
Copy link
Contributor Author

@wimrijnders Thanks.
I understand this still requires more work. It will be DRYed with further PRs

@yotamberk yotamberk merged commit fe49e7e into almende:develop Sep 29, 2017
@Areson
Copy link
Contributor

Areson commented Oct 1, 2017

@yotamberk @wimrijnders Since I've been working with the develop branch post the merging of this issue (for reference, the one I am working with is #3501), I've noticed that this causes the order of stacked items to no longer be consistent. Under the old redraw logic for groups (and in general?) the vertical ordering of items was consistent as the graph was scrolled horizontally. After this change the order of items appears to jump around erratically as you scroll horizontally, which really wrecks the usability of the timeline. I think I've narrowed it down to what causes it, but I don't know why.

Here is the old method. If I revert back to just this (leaving all other changes intact) then the vertical positioning is stable again:

util.forEach(this.items, function (item, key) {
        if (!item.displayed) {     
          item.redraw();            
          me.visibleItems.push(item);
        }
        item.repositionX(limitSize);
      });

If I make one adjustment to this to move back towards the code from the PR, the vertical position starts jumping around:

util.forEach(this.items, function (item, key) {
        if (!item.displayed) {       
          item.redraw();            
          me.visibleItems.push(item);
        }
      })

 for (var i = 0; i < this.items.length; i++) {
    this.items[i].repositionX(limitSize);
 }

@yotamberk
Copy link
Contributor Author

Great! Can you please submit a PR with this revert?

primozs pushed a commit to primozs/vis that referenced this pull request Jan 3, 2019
* Make items redraws return queues

* Parallel initial items redraw

* Seperate read and write actions in items

* Parallel all items redraws

* Remove comments

* Fix linting comments

* Fix redraws on actions

* Add stress example

* Fix example files

* Explain and fix example

* Fix comment issues
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants