diff --git a/src/Util.ts b/src/Util.ts index e0fdbbe8..757f014b 100644 --- a/src/Util.ts +++ b/src/Util.ts @@ -564,7 +564,7 @@ export const Util = { _isPlainObject(obj: any) { return !!obj && obj.constructor === Object; }, - _isArray(obj: any) { + _isArray(obj: any): obj is Array { return Object.prototype.toString.call(obj) === OBJECT_ARRAY; }, _isNumber(obj: any): obj is number { diff --git a/src/Validators.ts b/src/Validators.ts index d64e7f2e..c6f77768 100644 --- a/src/Validators.ts +++ b/src/Validators.ts @@ -48,6 +48,25 @@ export function getNumberValidator() { }; } } + +export function getNumberOrArrayOfNumbersValidator(noOfElements: number) { + if (Konva.isUnminified) { + return function (val: T, attr: string): T | void { + let isNumber = Util._isNumber(val); + let isValidArray = Util._isArray(val) && val.length == noOfElements; + if (!isNumber && !isValidArray) { + Util.warn( + _formatValue(val) + + ' is a not valid value for "' + + attr + + '" attribute. The value should be a number or Array(' + noOfElements + ')' + ); + } + return val; + }; + } +} + export function getNumberOrAutoValidator() { if (Konva.isUnminified) { return function (val: T, attr: string): T | void { diff --git a/src/shapes/Label.ts b/src/shapes/Label.ts index 6a4fedae..a30879e2 100644 --- a/src/shapes/Label.ts +++ b/src/shapes/Label.ts @@ -3,7 +3,7 @@ import { Factory } from '../Factory'; import { Shape, ShapeConfig } from '../Shape'; import { Group } from '../Group'; import { ContainerConfig } from '../Container'; -import { getNumberValidator } from '../Validators'; +import {getNumberOrArrayOfNumbersValidator, getNumberValidator} from '../Validators'; import { _registerNode } from '../Global'; import { GetSet } from '../types'; @@ -195,18 +195,32 @@ export interface TagConfig extends ShapeConfig { export class Tag extends Shape { _sceneFunc(context) { var width = this.width(), - height = this.height(), - pointerDirection = this.pointerDirection(), - pointerWidth = this.pointerWidth(), - pointerHeight = this.pointerHeight(), - cornerRadius = Math.min(this.cornerRadius(), width / 2, height / 2); + height = this.height(), + pointerDirection = this.pointerDirection(), + pointerWidth = this.pointerWidth(), + pointerHeight = this.pointerHeight(), + cornerRadius = this.cornerRadius(); + + let topLeft = 0; + let topRight = 0; + let bottomLeft = 0; + let bottomRight = 0; + + if (typeof cornerRadius === 'number') { + topLeft = topRight = bottomLeft = bottomRight = Math.min( + cornerRadius, + width / 2, + height / 2 + ); + } else { + topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2); + topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2); + bottomRight = Math.min(cornerRadius[2] || 0, width / 2, height / 2); + bottomLeft = Math.min(cornerRadius[3] || 0, width / 2, height / 2); + } context.beginPath(); - if (!cornerRadius) { - context.moveTo(0, 0); - } else { - context.moveTo(cornerRadius, 0); - } + context.moveTo(topLeft, 0); if (pointerDirection === UP) { context.lineTo((width - pointerWidth) / 2, 0); @@ -214,19 +228,15 @@ export class Tag extends Shape { context.lineTo((width + pointerWidth) / 2, 0); } - if (!cornerRadius) { - context.lineTo(width, 0); - } else { - context.lineTo(width - cornerRadius, 0); - context.arc( - width - cornerRadius, - cornerRadius, - cornerRadius, + context.lineTo(width - topRight, 0); + context.arc( + width - topRight, + topRight, + topRight, (Math.PI * 3) / 2, 0, false - ); - } + ); if (pointerDirection === RIGHT) { context.lineTo(width, (height - pointerHeight) / 2); @@ -234,19 +244,15 @@ export class Tag extends Shape { context.lineTo(width, (height + pointerHeight) / 2); } - if (!cornerRadius) { - context.lineTo(width, height); - } else { - context.lineTo(width, height - cornerRadius); - context.arc( - width - cornerRadius, - height - cornerRadius, - cornerRadius, + context.lineTo(width, height - bottomRight); + context.arc( + width - bottomRight, + height - bottomRight, + bottomRight, 0, Math.PI / 2, false - ); - } + ); if (pointerDirection === DOWN) { context.lineTo((width + pointerWidth) / 2, height); @@ -254,19 +260,15 @@ export class Tag extends Shape { context.lineTo((width - pointerWidth) / 2, height); } - if (!cornerRadius) { - context.lineTo(0, height); - } else { - context.lineTo(cornerRadius, height); - context.arc( - cornerRadius, - height - cornerRadius, - cornerRadius, + context.lineTo(bottomLeft, height); + context.arc( + bottomLeft, + height - bottomLeft, + bottomLeft, Math.PI / 2, Math.PI, false - ); - } + ); if (pointerDirection === LEFT) { context.lineTo(0, (height + pointerHeight) / 2); @@ -274,17 +276,14 @@ export class Tag extends Shape { context.lineTo(0, (height - pointerHeight) / 2); } - if (cornerRadius) { - context.lineTo(0, cornerRadius); - context.arc( - cornerRadius, - cornerRadius, - cornerRadius, + context.lineTo(0, topLeft); + context.arc( + topLeft, + topLeft, + topLeft, Math.PI, (Math.PI * 3) / 2, - false - ); - } + false); context.closePath(); context.fillStrokeShape(this); @@ -369,8 +368,12 @@ Factory.addGetterSetter(Tag, 'pointerHeight', 0, getNumberValidator()); * @returns {Number} * @example * tag.cornerRadius(20); + * + * // set different corner radius values + * // top-left, top-right, bottom-right, bottom-left + * tag.cornerRadius([0, 10, 20, 30]); */ -Factory.addGetterSetter(Tag, 'cornerRadius', 0, getNumberValidator()); +Factory.addGetterSetter(Tag, 'cornerRadius', 0, getNumberOrArrayOfNumbersValidator(4)); Collection.mapMethods(Tag); diff --git a/src/shapes/Rect.ts b/src/shapes/Rect.ts index 2911651c..941a4344 100644 --- a/src/shapes/Rect.ts +++ b/src/shapes/Rect.ts @@ -4,6 +4,7 @@ import { Shape, ShapeConfig } from '../Shape'; import { _registerNode } from '../Global'; import { GetSet } from '../types'; +import {getNumberOrArrayOfNumbersValidator} from "../Validators"; export interface RectConfig extends ShapeConfig { cornerRadius?: number | number[]; } @@ -49,10 +50,10 @@ export class Rect extends Shape { height / 2 ); } else { - topLeft = Math.min(cornerRadius[0], width / 2, height / 2); - topRight = Math.min(cornerRadius[1], width / 2, height / 2); - bottomRight = Math.min(cornerRadius[2], width / 2, height / 2); - bottomLeft = Math.min(cornerRadius[3], width / 2, height / 2); + topLeft = Math.min(cornerRadius[0] || 0, width / 2, height / 2); + topRight = Math.min(cornerRadius[1] || 0, width / 2, height / 2); + bottomRight = Math.min(cornerRadius[2] ||0, width / 2, height / 2); + bottomLeft = Math.min(cornerRadius[3] || 0, width / 2, height / 2); } context.moveTo(topLeft, 0); context.lineTo(width - topRight, 0); @@ -112,6 +113,6 @@ _registerNode(Rect); * // top-left, top-right, bottom-right, bottom-left * rect.cornerRadius([0, 10, 20, 30]); */ -Factory.addGetterSetter(Rect, 'cornerRadius', 0); +Factory.addGetterSetter(Rect, 'cornerRadius', 0, getNumberOrArrayOfNumbersValidator(4)); Collection.mapMethods(Rect); diff --git a/test/unit/shapes/Label-test.js b/test/unit/shapes/Label-test.js index 620291a7..42445fa7 100644 --- a/test/unit/shapes/Label-test.js +++ b/test/unit/shapes/Label-test.js @@ -269,4 +269,33 @@ suite('Label', function () { layer.draw(); assert.equal(tag.width(), text.width()); }); + + test("tag cornerRadius", function() { + var stage = addStage(); + var layer = new Konva.Layer(); + + var tag = new Konva.Tag({ + x: 50, + y: 50, + width: 100, + height: 100, + fill: 'black', + cornerRadius: [0, 10, 20, 30], + }); + layer.add(tag); + stage.add(layer); + layer.draw(); + + assert.equal(tag.cornerRadius()[0], 0); + assert.equal(tag.cornerRadius()[1], 10); + assert.equal(tag.cornerRadius()[2], 20); + assert.equal(tag.cornerRadius()[3], 30); + + + var trace = layer.getContext().getTrace(); + assert.equal( + trace, + 'clearRect(0,0,578,200);save();transform(1,0,0,1,50,50);beginPath();moveTo(0,0);lineTo(90,0);arc(90,10,10,4.712,0,false);lineTo(100,80);arc(80,80,20,0,1.571,false);lineTo(30,100);arc(30,70,30,1.571,3.142,false);lineTo(0,0);arc(0,0,0,3.142,4.712,false);closePath();fillStyle=black;fill();restore();clearRect(0,0,578,200);save();transform(1,0,0,1,50,50);beginPath();moveTo(0,0);lineTo(90,0);arc(90,10,10,4.712,0,false);lineTo(100,80);arc(80,80,20,0,1.571,false);lineTo(30,100);arc(30,70,30,1.571,3.142,false);lineTo(0,0);arc(0,0,0,3.142,4.712,false);closePath();fillStyle=black;fill();restore();' + ); + }); });