diff --git a/src/AbsoluteRenderOrderGroup.ts b/src/AbsoluteRenderOrderGroup.ts index 644c03e8..1d59f0a8 100644 --- a/src/AbsoluteRenderOrderGroup.ts +++ b/src/AbsoluteRenderOrderGroup.ts @@ -122,16 +122,19 @@ export class AbsoluteRenderOrderGroup extends Group { }); } else { // Is a leaf / don't descend farther -- this can be added to children map - let zOrder:number = node.zOrder(); + // Determine zOrder + let zOrder:number = node.evaluateZOrderRecursively(); + + // Add zOrder if needed if (!orderedChildren.has(zOrder)) { orderedChildren.set(zOrder, new Array()); } + // Add to the correct bucket of zOrders orderedChildren.get(zOrder).push(node); // I'd much prefer the [] syntax for clarity, but seems TS/JS doesn't seem to support it, ugh. } } - } //AbsoluteRenderOrderGroup.prototype.nodeType = 'AbsoluteRenderOrderGroup'; diff --git a/src/Node.ts b/src/Node.ts index 5f322b9a..a3e7a78d 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -2574,6 +2574,21 @@ export abstract class Node { return Util.haveIntersection(screenRect, this.getClientRect()); } + /** + * Utility function to evaluate the zOrder of a node. This differs from just checking the zOrder() as this function + * will check parents to inherit a zOrder value if this node does not have one set. Otherwise, if no zOrders are set + * recursively, this will return 0 (this function will not return undefined). + * @returns {number} + */ + evaluateZOrderRecursively():number { + if (this.zOrder() != undefined) + return this.zOrder(); + if (this.parent == null) + return 0; + else + return this.parent.evaluateZOrderRecursively(); + } + preventDefault: GetSet; // from filters @@ -2619,7 +2634,7 @@ export abstract class Node { rotation: GetSet; zIndex: GetSet; - zOrder: GetSet; + zOrder: GetSet; scale: GetSet; scaleX: GetSet; @@ -3285,9 +3300,14 @@ addGetterSetter(Node, 'draggable', false, getBooleanValidator()); * AbsoluteRenderOrderContainer to recursively render child objects in an absolute z-order. This field will otherwise * be ignored. Alternatively, you can use the z-index features to move an object within a particular group, relative to * the other nodes in the group. + * + * If not set (/set to undefined), the z-order of the parent (recursively) will be inherited. If no z-orders are set + * through parents, the default z-order is 0. + * + * Higher z-orders will be rendered on top of lower z-orders. * @name Konva.Node#zOrder * @method - * @param {Number} zOrder + * @param {Number | undefined} zOrder * @returns {Object} * @example * // get z-order @@ -3295,9 +3315,12 @@ addGetterSetter(Node, 'draggable', false, getBooleanValidator()); * * // set z-order * node.zOrder(5); + * + * // unset z-order + * node.zOrder(undefined); */ -addGetterSetter(Node, 'zOrder', 0, getNumberValidator()); +addGetterSetter(Node, 'zOrder', undefined, getNumberValidator()); Factory.backCompat(Node, { rotateDeg: 'rotate', diff --git a/test/unit/AbsoluteRenderOrderGroup-test.ts b/test/unit/AbsoluteRenderOrderGroup-test.ts index 9800cb84..33cef5bf 100644 --- a/test/unit/AbsoluteRenderOrderGroup-test.ts +++ b/test/unit/AbsoluteRenderOrderGroup-test.ts @@ -138,4 +138,71 @@ describe('AbsoluteRenderOrderGroup', function () { assert.equal(red3, 119, "Did not find correct amount of red in medium dark red pixel for test 1, ordering is possibly incorrect. Red amount found was: " + red3); assert.equal(black, 0, "Did not find correct amount of red in black pixel for test 1, ordering is possibly incorrect. Red amount found was: " + black); }); + + it('check render order inherits null correctly', function () { + var stage = addStage(); + + const layer = new Konva.Layer(); + stage.add(layer); + + // This will test that AbsoluteRenderOrderGroup renders based on z-order, not z-index + const absoluteRenderOrderGroupTest = new Konva.AbsoluteRenderOrderGroup({ + x: 0, + y: 0 + }); + layer.add(absoluteRenderOrderGroupTest); + + const redRect = new Konva.Rect({ + zOrder: 5, + width: 100, + height: 100, + fill: 'red' + }); + absoluteRenderOrderGroupTest.add(redRect); + + const groupInheritanceTest = new Konva.Group(); + absoluteRenderOrderGroupTest.add(groupInheritanceTest); + + const groupInheritanceTest2 = new Konva.Group(); + groupInheritanceTest.add(groupInheritanceTest2); + + const blueRect = new Konva.Rect({ + x: 0, + y: 0, + width: 100, + height: 100, + fill: 'blue' + }); + groupInheritanceTest2.add(blueRect); + + layer.draw(); + + // Check default z-order. + // When looking at pixel color rendered, should be Red as the red rect has higher z-order priority than the + // blue rect, which at this point should be defaulting to 0 + let context = layer.canvas.getContext(); + let imageData = context.getImageData(55, 55, 1, 1); // this is an intersecting pixel location between red & blue + let red = imageData.data[0]; + + assert.equal(red, 255, "Default test: Did not find red pixel, unexpected defaulting. Red amount found was: " + red); + + // Test setting immediate parent higher and check that blue rect inherits it + groupInheritanceTest2.zOrder(10); + layer.draw(); + + imageData = context.getImageData(55, 55, 1, 1); // this is an intersecting pixel location between red & blue + let blue = imageData.data[2]; + + assert.equal(blue, 255, "Immediate parent test: did not find blue pixel, unexpected defaulting. Red amount found was: " + red); + + // Test setting parent of parent and check that blue rect inherits it + groupInheritanceTest.zOrder(10); + groupInheritanceTest2.zOrder(undefined); + layer.draw(); + + imageData = context.getImageData(55, 55, 1, 1); // this is an intersecting pixel location between red & blue + blue = imageData.data[2]; + + assert.equal(blue, 255, "Immediate parent test: did not find blue pixel, unexpected defaulting. Red amount found was: " + red); + }); }); \ No newline at end of file