Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Layout service supports configuring box order #3812

Merged
merged 2 commits into from
Feb 25, 2017
Merged

Layout service supports configuring box order #3812

merged 2 commits into from
Feb 25, 2017

Conversation

etimberg
Copy link
Member

Resolves #3388

The layout system now supports an order property which is used to align left and right boxes. A higher value is further away from the chart. This should not change the axis positions, and I did not observe any differences. It may be prudent to wait until v2.6 to include this.

After Fix

screen shot 2017-01-20 at 5 30 30 pm

/**
* Register a box to a chartInstance.
* A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
* @method Chart.layoutService.addBox
Copy link
Member Author

Choose a reason for hiding this comment

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

I did this documentation method based on http://stackoverflow.com/a/6460748 because it generated less docs than doing something to define an interface. Once we have gulp docs in, I can test this and see what it generates

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, that works well for nested arguments, but I think here it's really an interface and it's quite weird to have these left, top, right, bottom properties part of the function inputs. This method expects an object that implements the IBox (or ILayoutBox or ILayoutItem) interface, as we have for IPlugin, IPlatform or IEvent. Also more convenient if we need to refer to that interface from somewhere in the doc.

Actually, it doesn't require so much more doc if you define the interface as I did for IEvent.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I will update to follow the same way as IEvent


// Ensure that all boxes have an order
if (!box.order) {
box.order = 0;
Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure about this. sort is not stable, so I don't think this guarantees the order of boxes. It might be better so simply set box.order = chartInstance.boxes.length so that it's more likely to be a unique value.

Copy link
Member

Choose a reason for hiding this comment

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

Default order should be 0, because boxes can be registered from anywhere, so it would be impossible to really control the box order:

addBox(chart, {});              // foo (index 0)
addBox(chart, {order: 1});      // bar (index 1)
addBox(chart, {});              // xyz (index 2)

Effective order is:

  • case default to 0: [foo, xyz, bar] (expected)
  • case auto-increment: [foo, bar, xyz]

Instead, we could use the box index as second sort criteria to obtain a stable sort:

function sort(array, reverse) {
    return array.map(function(v, i) {
        v._tmp_index_ = i;
    })
    .sort(function (a, b) {
        var v0 = reverse? b : a;
        var v1 = reverse? a : b;
        return v0.order === v1.order?
            v0._tmp_index_ - v1._tmp_index_ :
            v0.order - v1.order;
    })
    .map(function(v) {
        delete v._tmp_index_;
    });
}

update: function() {
    sort(leftBoxes, false);
    sort(rightBoxes, true);
    sort(topBoxes, false);
    sort(bottomBoxes, true);
}

Not super efficient, but I don't think there will be so much boxes to sort!

@@ -79,6 +113,14 @@ module.exports = function(Chart) {
return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0);
});

// Ensure that boxes are sorted by order. Higher order means further away from the chart
leftBoxes.sort(function(a, b) {
Copy link
Member Author

Choose a reason for hiding this comment

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

Should we apply this to top and bottom boxes as well? If so, we need to change the sorts just above here

Copy link
Member

Choose a reason for hiding this comment

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

I think so, maybe options.fullWidth should not be used anymore to control the box order.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's probably a good idea. I will make that change

@etimberg etimberg added this to the Version 2.6 milestone Jan 20, 2017

// Ensure that all boxes have an order
if (!box.order) {
box.order = 0;
Copy link
Member

Choose a reason for hiding this comment

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

Default order should be 0, because boxes can be registered from anywhere, so it would be impossible to really control the box order:

addBox(chart, {});              // foo (index 0)
addBox(chart, {order: 1});      // bar (index 1)
addBox(chart, {});              // xyz (index 2)

Effective order is:

  • case default to 0: [foo, xyz, bar] (expected)
  • case auto-increment: [foo, bar, xyz]

Instead, we could use the box index as second sort criteria to obtain a stable sort:

function sort(array, reverse) {
    return array.map(function(v, i) {
        v._tmp_index_ = i;
    })
    .sort(function (a, b) {
        var v0 = reverse? b : a;
        var v1 = reverse? a : b;
        return v0.order === v1.order?
            v0._tmp_index_ - v1._tmp_index_ :
            v0.order - v1.order;
    })
    .map(function(v) {
        delete v._tmp_index_;
    });
}

update: function() {
    sort(leftBoxes, false);
    sort(rightBoxes, true);
    sort(topBoxes, false);
    sort(bottomBoxes, true);
}

Not super efficient, but I don't think there will be so much boxes to sort!

/**
* Register a box to a chartInstance.
* A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
* @method Chart.layoutService.addBox
Copy link
Member

Choose a reason for hiding this comment

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

Indeed, that works well for nested arguments, but I think here it's really an interface and it's quite weird to have these left, top, right, bottom properties part of the function inputs. This method expects an object that implements the IBox (or ILayoutBox or ILayoutItem) interface, as we have for IPlugin, IPlatform or IEvent. Also more convenient if we need to refer to that interface from somewhere in the doc.

Actually, it doesn't require so much more doc if you define the interface as I did for IEvent.

/**
* Register a box to a chartInstance.
* A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
* @method Chart.layoutService.addBox
Copy link
Member

Choose a reason for hiding this comment

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

We shouldn't need to define @method since it's part of the Chart.layoutService object.

* @param {Core.Controller} chartInstance the chart to use
* @param {Object} box the box to add
* @param {Number} box.order the order of the boxes. Higher numbers are further away from the chart area
* @param box.options Options for configuring the box
Copy link
Member

Choose a reason for hiding this comment

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

Why are there some options under box.options and some others directly under box?

chartInstance.boxes.push(box);
},

/**
* Remove a box from a chart
* @param {Core.Controller} chartInstance the chart to remove the box from
Copy link
Member

Choose a reason for hiding this comment

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

Should be {Chart.Controller} to bind that parameter to the controller doc.

@@ -79,6 +113,14 @@ module.exports = function(Chart) {
return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0);
});

// Ensure that boxes are sorted by order. Higher order means further away from the chart
leftBoxes.sort(function(a, b) {
Copy link
Member

Choose a reason for hiding this comment

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

I think so, maybe options.fullWidth should not be used anymore to control the box order.

@simonbrunel
Copy link
Member

Can we rename order into weight instead?

@etimberg
Copy link
Member Author

I will change order to weight, apply it to the top and bottom boxes as well. I will also update the documentation and update the title to use the new weight field

@etimberg
Copy link
Member Author

@simonbrunel when you get a chance, can you review this after the changes?

@simonbrunel
Copy link
Member

Should we add unit tests?

@etimberg
Copy link
Member Author

@simonbrunel I'll add some tests to ensure that the sorting and stuff works as expected.

@etimberg etimberg merged commit b50eac3 into master Feb 25, 2017
@etimberg etimberg deleted the fix/3388 branch February 25, 2017 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants