Skip to content

Commit

Permalink
feat(grid): allow setting alignment for individual rows or cols, allo…
Browse files Browse the repository at this point in the history
…w setting children (#260)

* feat(grid): allow setting alignment for individual rows or cols, allow setting children

* fix ts
  • Loading branch information
straker authored Nov 28, 2021
1 parent d028625 commit ef9befd
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 19 deletions.
13 changes: 12 additions & 1 deletion src/gameObject.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ class GameObject extends Updatable {
...props
} = {}) {
// @ifdef GAMEOBJECT_GROUP
this.children = [];
this._c = [];
// @endif

// by setting defaults to the parameters and passing them into
Expand Down Expand Up @@ -549,6 +549,17 @@ class GameObject extends Updatable {
// --------------------------------------------------

// @ifdef GAMEOBJECT_GROUP
set children(value) {
while (this._c.length) {
this.removeChild(this._c[0]);
}
value.map(value => this.addChild(value));
}

get children() {
return this._c;
}

/**
* Add an object as a child to this object. The childs [world](api/gameObject#world) property will be updated to take into account this object and all of its parents.
* @memberof GameObject
Expand Down
41 changes: 25 additions & 16 deletions src/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ let alignment = {
*
* @param {Object} [properties] - Properties of the grid manager.
* @param {String} [properties.flow='column'] - The flow of the grid.
* @param {String} [properties.align='start'] - The vertical alignment of the grid.
* @param {String} [properties.justify='start'] - The horizontal alignment of the grid.
* @param {String|String[]} [properties.align='start'] - The vertical alignment of the grid.
* @param {String|String[]} [properties.justify='start'] - The horizontal alignment of the grid.
* @param {Number|Number[]} [properties.colGap=0] - The horizontal gap between each column in the grid.
* @param {Number|Number[]} [properties.rowGap=0] - The vertical gap between each row in the grid.
* @param {Number} [properties.numCols=1] - The number of columns in the grid. Only applies if the `flow` property is set to `grid`.
Expand Down Expand Up @@ -62,9 +62,11 @@ class Grid extends GameObjectClass {
* - `center` - align to the center of the row
* - `end` - align to the the bottom of the row
*
* An array of strings means the grid will set the vertical alignment for each row using the order of the array. For example, if the alignment is set to be `[`end`, 'start']`, then every odd row will use 'end' and every even row will use 'start'.
*
* Additionally, each child of the grid can use the `alignSelf` property to change it's alignment in the grid.
* @memberof Grid
* @property {String} align
* @property {String|String[]} align
*/
align = 'start',

Expand All @@ -75,18 +77,20 @@ class Grid extends GameObjectClass {
* - `center` - align to the center of the column
* - `end` - align to the the right of the column
*
* An array of strings means the grid will set the horizontal alignment for each column using the order of the array. For example, if the alignment is set to be `[`end`, 'start']`, then every odd column will use 'end' and every even column will use 'start'.
*
* If the [dir](api/grid#dir) property is set to `rtl`, then `start` and `end` are reversed.
*
* Additionally, each child of the grid can use the `justifySelf` property to change it's alignment in the grid.
* @memberof Grid
* @property {String} justify
* @property {String|String[]} justify
*/
justify = 'start',

/**
* The horizontal gap between each column in the grid.
*
* An array of numbers means the grid will set the gap between columns using the order of the array. For example, if the gap is set to be `[10, 5]`, then every odd column gap with use 10 and every even column gap will use 5.
* An array of numbers means the grid will set the gap between columns using the order of the array. For example, if the gap is set to be `[10, 5]`, then every odd column gap will use 10 and every even column gap will use 5.
* @memberof Grid
* @property {Number|Number[]} colGap
*/
Expand All @@ -95,7 +99,7 @@ class Grid extends GameObjectClass {
/**
* The vertical gap between each row in the grid.
*
* An array of numbers means the grid will set the gap between rows using the order of the array. For example, if the gap is set to be `[10, 5]`, then every odd row gap with use 10 and every even row gap will use 5.
* An array of numbers means the grid will set the gap between rows using the order of the array. For example, if the gap is set to be `[10, 5]`, then every odd row gap will use 10 and every even row gap will use 5.
* @memberof Grid
* @property {Number|Number[]} rowGap
*/
Expand Down Expand Up @@ -281,6 +285,9 @@ class Grid extends GameObjectClass {
let topLeftY = -this.anchor.y * this.height;
let rendered = [];

let justify = [].concat(this.justify);
let align = [].concat(this.align);

this._g.map((gridRow, row) => {
let topLeftX = -this.anchor.x * this.width;

Expand All @@ -289,8 +296,10 @@ class Grid extends GameObjectClass {
if (child && !rendered.includes(child)) {
rendered.push(child);

let justify = alignment[child.justifySelf || this.justify](this._rtl);
let align = alignment[child.alignSelf || this.align]();
let justifySelf = alignment[child.justifySelf || justify[col % justify.length]](
this._rtl
);
let alignSelf = alignment[child.alignSelf || align[row % align.length]]();

let colSpan = child.colSpan || 1;
let colWidth = colWidths[col];
Expand All @@ -300,8 +309,8 @@ class Grid extends GameObjectClass {
}
}

let pointX = colWidth * justify;
let pointY = rowHeights[row] * align;
let pointX = colWidth * justifySelf;
let pointY = rowHeights[row] * alignSelf;
let anchorX = 0;
let anchorY = 0;
let { width, height } = child.world || child;
Expand All @@ -313,22 +322,22 @@ class Grid extends GameObjectClass {

// calculate the x position based on the alignment and
// anchor of the object
if (justify === 0) {
if (justifySelf === 0) {
pointX = pointX + width * anchorX;
} else if (justify === 0.5) {
} else if (justifySelf === 0.5) {
let sign = anchorX < 0.5 ? -1 : anchorX === 0.5 ? 0 : 1;
pointX = pointX + sign * width * justify;
pointX = pointX + sign * width * justifySelf;
} else {
pointX = pointX - width * (1 - anchorX);
}

// calculate the y position based on the justification and
// anchor of the object
if (align === 0) {
if (alignSelf === 0) {
pointY = pointY + height * anchorY;
} else if (align === 0.5) {
} else if (alignSelf === 0.5) {
let sign = anchorY < 0.5 ? -1 : anchorY === 0.5 ? 0 : 1;
pointY = pointY + sign * height * align;
pointY = pointY + sign * height * alignSelf;
} else {
pointY = pointY - height * (1 - anchorY);
}
Expand Down
10 changes: 8 additions & 2 deletions test/typings/grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import * as kontra from '../../kontra.js';
let grid = kontra.Grid();

let flow: string = grid.flow;
let align: string = grid.align;
let justify: string = grid.justify;
let align: string | string[] = grid.align;
let justify: string | string[] = grid.justify;
let colGap: number | number[] = grid.colGap;
let rowGap: number | number[] = grid.rowGap;
let numRows: number = grid.numRows;
Expand Down Expand Up @@ -40,6 +40,12 @@ kontra.Grid({
rowGap: [10],
});

// alignment arrays
kontra.Grid({
align: ['end', 'center'],
justify: ['end', 'center'],
});

// extends
class CustomGrid extends kontra.GridClass {}
let myGrid = new CustomGrid();
Expand Down
30 changes: 30 additions & 0 deletions test/unit/gameObject.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,36 @@ describe('gameObject with context: ' + JSON.stringify(testContext, null, 4), ()
}
});

// --------------------------------------------------
// children
// --------------------------------------------------
describe('children', () => {
if (testContext.GAMEOBJECT_GROUP) {
it('should properly handle setting children', () => {
gameObject.addChild({ foo: 'bar' });
gameObject.addChild({ faz: 'baz' });
gameObject.addChild({ hello: 'world' });

let removeSpy = sinon.spy(gameObject, 'removeChild');
let addSpy = sinon.spy(gameObject, 'addChild');
let child = {
thing1: 'thing2'
};

gameObject.children = [child];

expect(removeSpy.calledThrice).to.be.true;
expect(addSpy.calledWith(child)).to.be.true;
expect(gameObject.children.length).to.equal(1);
expect(gameObject.children[0]).to.equal(child);
});
} else {
it('should not have children', () => {
expect(gameObject.children).to.not.exist;
});
}
});

// --------------------------------------------------
// update
// --------------------------------------------------
Expand Down
34 changes: 34 additions & 0 deletions test/unit/grid.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,23 @@ describe('grid', () => {
expect(child4.y).to.equal(100);
});

it('should take into account align array', () => {
grid.align = ['center', 'end'];
grid.render();

expect(child1.x).to.equal(0);
expect(child1.y).to.equal(37.5);

expect(child2.x).to.equal(100);
expect(child2.y).to.equal(0);

expect(child3.x).to.equal(0);
expect(child3.y).to.equal(125);

expect(child4.x).to.equal(100);
expect(child4.y).to.equal(100);
});

it('should take into account child with `alignSelf`', () => {
child1.alignSelf = 'center';
grid._d = true;
Expand Down Expand Up @@ -653,6 +670,23 @@ describe('grid', () => {
expect(child4.y).to.equal(100);
});

it('should take into account justify array', () => {
grid.justify = ['center', 'end'];
grid.render();

expect(child1.x).to.equal(0);
expect(child1.y).to.equal(0);

expect(child2.x).to.equal(100);
expect(child2.y).to.equal(0);

expect(child3.x).to.equal(25);
expect(child3.y).to.equal(100);

expect(child4.x).to.equal(100);
expect(child4.y).to.equal(100);
});

it('should take into account child with `justifySelf`', () => {
child3.justifySelf = 'center';
grid._d = true;
Expand Down

0 comments on commit ef9befd

Please sign in to comment.