From 8bb59548e59593a730c6b978d9ed2fdfefe21fdf Mon Sep 17 00:00:00 2001 From: Adam L Date: Wed, 21 Mar 2018 19:03:38 -0700 Subject: [PATCH 1/2] add findWhere method to Containers --- konva.d.ts | 1 + src/Container.js | 46 +++++++++++++++++++++++++++++++++++++ test/unit/Container-test.js | 31 +++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/konva.d.ts b/konva.d.ts index a39e8557..37ae923e 100644 --- a/konva.d.ts +++ b/konva.d.ts @@ -324,6 +324,7 @@ declare namespace Konva { clipFunc(ctx: CanvasRenderingContext2D | undefined | null): void; destroyChildren(): void; find(selector?: string): Collection; + findWhere(fn: (Node) => boolean): Collection; findOne(selector: string): T; getAllIntersections(pos: Vector2d): Shape[]; hasChildren(): boolean; diff --git a/src/Container.js b/src/Container.js index bc8bb90d..c031a17d 100644 --- a/src/Container.js +++ b/src/Container.js @@ -227,6 +227,52 @@ findOne: function(selector) { return this.find(selector)[0]; }, + /** + * return a {@link Konva.Collection} of nodes that return true when passed through your function argument. + * Your function has access to the currentNode argument, and should return a boolean type. + * See examples for more details. + * @method + * @memberof Konva.Container.prototype + * @param {Function} fn + * @returns {Collection} + * @example + * // get all Groups + * var groups = stage.findWhere(el => { + * return el.getType() === 'Group'; + * }); + * + * // get only Nodes with partial opacity + * var alphaNodes = layer.findWhere(el => { + * return el.getType() === 'Node' && el.getAbsoluteOpacity() < 1; + * }); + */ + findWhere: function(fn) { + if (typeof fn !== 'function') { + Konva.Util.warn( + 'You must pass a function with a return value as your argument here. Are you maybe looking for .find instead?' + ); + Konva.Util.warn('Konva is awesome, right?'); + } + + var retArr = []; + + var addItems = function(el) { + var children = el.getChildren(); + var clen = children.length; + + if (fn(el)) { + retArr = retArr.concat(el); + } + + for (var i = 0; i < clen; i++) { + addItems(children[i]); + } + }; + + addItems(this); + + return Konva.Collection.toCollection(retArr); + }, _getNodeById: function(key) { var node = Konva.ids[key]; diff --git a/test/unit/Container-test.js b/test/unit/Container-test.js index a47d9755..a0e129be 100644 --- a/test/unit/Container-test.js +++ b/test/unit/Container-test.js @@ -406,6 +406,37 @@ suite('Container', function() { ); }); + // ====================================================== + test('select shape by function', function() { + var stage = addStage(); + var layer = new Konva.Layer(); + + var rect = new Konva.Rect({ + x: 300, + y: 100, + width: 100, + height: 50, + fill: 'purple', + stroke: 'black', + strokeWidth: 4, + name: 'myRect' + }); + + layer.add(rect); + stage.add(layer); + + var fn = function(node) { + return node.nodeType === 'Shape'; + }; + + var noOp = function(node) { + return false; + }; + + assert.equal(stage.findWhere(fn)[0], rect); + assert.equal(stage.findWhere(noOp).length, 0); + }); + // ====================================================== test('set x on an array of nodes', function() { var stage = addStage(); From a2c342cf6ebd71d28c42b9de40f0df69716c3b64 Mon Sep 17 00:00:00 2001 From: Adam L Date: Sat, 24 Mar 2018 16:29:41 -0700 Subject: [PATCH 2/2] migrate find fn to single method --- konva.d.ts | 40 ++++++++++----- src/Container.js | 97 +++++++++++++++++++------------------ test/unit/Container-test.js | 4 +- 3 files changed, 80 insertions(+), 61 deletions(-) diff --git a/konva.d.ts b/konva.d.ts index 37ae923e..24982724 100644 --- a/konva.d.ts +++ b/konva.d.ts @@ -5,15 +5,34 @@ declare namespace Konva { var isDragReady: () => boolean; var DD: any; - type globalCompositeOperationType = '' | - 'source-over' | 'source-in' | 'source-out' | 'source-atop' | - 'destination-over' | 'destination-in' | 'destination-out' | 'destination-atop' | - 'lighter' | 'copy' | 'xor' | 'multiply' | - 'screen' | 'overlay' | 'darken' | 'lighten' | - 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | - 'difference' | 'exclusion' | 'hue' | 'saturation' | - 'color' | 'luminosity' - ; + type globalCompositeOperationType = + | '' + | 'source-over' + | 'source-in' + | 'source-out' + | 'source-atop' + | 'destination-over' + | 'destination-in' + | 'destination-out' + | 'destination-atop' + | 'lighter' + | 'copy' + | 'xor' + | 'multiply' + | 'screen' + | 'overlay' + | 'darken' + | 'lighten' + | 'color-dodge' + | 'color-burn' + | 'hard-light' + | 'soft-light' + | 'difference' + | 'exclusion' + | 'hue' + | 'saturation' + | 'color' + | 'luminosity'; export class Util { static getRandomColor(): string; @@ -323,8 +342,7 @@ declare namespace Konva { clipFunc(): (ctx: CanvasRenderingContext2D) => void; clipFunc(ctx: CanvasRenderingContext2D | undefined | null): void; destroyChildren(): void; - find(selector?: string): Collection; - findWhere(fn: (Node) => boolean): Collection; + find(selector?: string | ((Node) => boolean)): Collection; findOne(selector: string): T; getAllIntersections(pos: Vector2d): Shape[]; hasChildren(): boolean; diff --git a/src/Container.js b/src/Container.js index c031a17d..d7abb147 100644 --- a/src/Container.js +++ b/src/Container.js @@ -141,14 +141,18 @@ return this; }, /** - * return a {@link Konva.Collection} of nodes that match the selector. Use '#' for id selections - * and '.' for name selections. You can also select by type or class name. Pass multiple selectors + * return a {@link Konva.Collection} of nodes that match the selector. + * You can provide a string with '#' for id selections and '.' for name selections. + * Or a function that will return true/false when a node is passed through. See example below. + * With strings you can also select by type or class name. Pass multiple selectors * separated by a space. * @method * @memberof Konva.Container.prototype - * @param {String} selector + * @param {String | Function} selector * @returns {Collection} * @example + * + * Passing a string as a selector * // select node with id foo * var node = stage.find('#foo'); * @@ -163,8 +167,47 @@ * * // select node with an id of foo or a name of bar inside layer * var nodes = layer.find('#foo, .bar'); + * + * Passing a function as a selector + * + * // get all Groups + * var groups = stage.find(node => { + * return node.getType() === 'Group'; + * }); + * + * // get only Nodes with partial opacity + * var alphaNodes = layer.find(node => { + * return node.getType() === 'Node' && node.getAbsoluteOpacity() < 1; + * }); */ find: function(selector) { + var retArr = []; + + if (typeof selector === 'string') { + retArr = this._findByString(selector); + } else if (typeof selector === 'function') { + retArr = this._findByFunction(selector); + } + + return Konva.Collection.toCollection(retArr); + }, + /** + * return a first node from `find` method + * @method + * @memberof Konva.Container.prototype + * @param {String} selector + * @returns {Konva.Node} + * @example + * // select node with id foo + * var node = stage.findOne('#foo'); + * + * // select node with name bar inside layer + * var nodes = layer.findOne('.bar'); + */ + findOne: function(selector) { + return this.find(selector)[0]; + }, + _findByString: function(selector) { var retArr = [], selectorArr = selector.replace(/ /g, '').split(','), len = selectorArr.length, @@ -209,51 +252,9 @@ } } - return Konva.Collection.toCollection(retArr); + return retArr; }, - /** - * return a first node from `find` method - * @method - * @memberof Konva.Container.prototype - * @param {String} selector - * @returns {Konva.Node} - * @example - * // select node with id foo - * var node = stage.findOne('#foo'); - * - * // select node with name bar inside layer - * var nodes = layer.findOne('.bar'); - */ - findOne: function(selector) { - return this.find(selector)[0]; - }, - /** - * return a {@link Konva.Collection} of nodes that return true when passed through your function argument. - * Your function has access to the currentNode argument, and should return a boolean type. - * See examples for more details. - * @method - * @memberof Konva.Container.prototype - * @param {Function} fn - * @returns {Collection} - * @example - * // get all Groups - * var groups = stage.findWhere(el => { - * return el.getType() === 'Group'; - * }); - * - * // get only Nodes with partial opacity - * var alphaNodes = layer.findWhere(el => { - * return el.getType() === 'Node' && el.getAbsoluteOpacity() < 1; - * }); - */ - findWhere: function(fn) { - if (typeof fn !== 'function') { - Konva.Util.warn( - 'You must pass a function with a return value as your argument here. Are you maybe looking for .find instead?' - ); - Konva.Util.warn('Konva is awesome, right?'); - } - + _findByFunction: function(fn) { var retArr = []; var addItems = function(el) { @@ -271,7 +272,7 @@ addItems(this); - return Konva.Collection.toCollection(retArr); + return retArr; }, _getNodeById: function(key) { var node = Konva.ids[key]; diff --git a/test/unit/Container-test.js b/test/unit/Container-test.js index a0e129be..14c27169 100644 --- a/test/unit/Container-test.js +++ b/test/unit/Container-test.js @@ -433,8 +433,8 @@ suite('Container', function() { return false; }; - assert.equal(stage.findWhere(fn)[0], rect); - assert.equal(stage.findWhere(noOp).length, 0); + assert.equal(stage.find(fn)[0], rect); + assert.equal(stage.find(noOp).length, 0); }); // ======================================================