UNPKG

konva

Version:

HTML5 2d canvas library for interactive graphics, design editors, whiteboards, and diagrams.

253 lines (252 loc) 8.33 kB
import { Factory } from "../Factory.js"; import { Util } from "../Util.js"; import { Shape } from "../Shape.js"; import { Group } from "../Group.js"; import { getNumberOrArrayOfNumbersValidator, getNumberValidator, } from "../Validators.js"; import { _registerNode } from "../Global.js"; import { Text } from "./Text.js"; // constants const ATTR_CHANGE_LIST = [ ...Text.prototype._attrsAffectingSize, 'width', 'height', 'pointerDirection', 'pointerWidth', 'pointerHeight', ], CHANGE_EVENTS = ATTR_CHANGE_LIST.map((attr) => attr + 'Change.konva').join(' '), NONE = 'none', UP = 'up', RIGHT = 'right', DOWN = 'down', LEFT = 'left'; /** * Label constructor.  Labels are groups that contain a Text and Tag shape * @constructor * @memberof Konva * @param {Object} config * @@nodeParams * @example * // create label * var label = new Konva.Label({ * x: 100, * y: 100, * draggable: true * }); * * // add a tag to the label * label.add(new Konva.Tag({ * fill: '#bbb', * stroke: '#333', * shadowColor: 'black', * shadowBlur: 10, * shadowOffset: { x: 10, y: 10 }, * shadowOpacity: 0.2, * lineJoin: 'round', * pointerDirection: 'up', * pointerWidth: 20, * pointerHeight: 20, * cornerRadius: 5 * })); * * // add text to the label * label.add(new Konva.Text({ * text: 'Hello World!', * fontSize: 50, * lineHeight: 1.2, * padding: 10, * fill: 'green' * })); */ export class Label extends Group { constructor(config) { super(config); this._sync = this._sync.bind(this); this.on('add.konva', function (evt) { // re-adding the same child must not stack another listener evt.child.off(CHANGE_EVENTS, this._sync).on(CHANGE_EVENTS, this._sync); this._sync(); }); } /** * get Text shape for the label. You need to access the Text shape in order to update * the text properties * @name Konva.Label#getText * @method * @example * label.getText().fill('red') */ getText() { return this.find('Text')[0]; } /** * get Tag shape for the label. You need to access the Tag shape in order to update * the pointer properties and the corner radius * @name Konva.Label#getTag * @method */ getTag() { return this.find('Tag')[0]; } getWidth() { return this.getText().width(); } getHeight() { return this.getText().height(); } _sync() { let text = this.getText(), tag = this.getTag(), width, height, pointerDirection, pointerWidth, x, y, pointerHeight; if (text && tag) { width = text.width(); height = text.height(); pointerDirection = tag.pointerDirection(); pointerWidth = tag.pointerWidth(); pointerHeight = tag.pointerHeight(); x = 0; y = 0; switch (pointerDirection) { case UP: x = width / 2; y = -1 * pointerHeight; break; case RIGHT: x = width + pointerWidth; y = height / 2; break; case DOWN: x = width / 2; y = height + pointerHeight; break; case LEFT: x = -1 * pointerWidth; y = height / 2; break; } tag.setAttrs({ x: -1 * x, y: -1 * y, width: width, height: height, }); text.setAttrs({ x: -1 * x, y: -1 * y, }); } } } Label.prototype.className = 'Label'; _registerNode(Label); /** * Tag constructor.  A Tag can be configured * to have a pointer element that points up, right, down, or left * @constructor * @memberof Konva * @param {Object} config * @param {String} [config.pointerDirection] can be up, right, down, left, or none; the default * is none. When a pointer is present, the positioning of the label is relative to the tip of the pointer. * @param {Number} [config.pointerWidth] * @param {Number} [config.pointerHeight] * @param {Number} [config.cornerRadius] */ export class Tag extends Shape { _sceneFunc(context) { const width = this.width(), height = this.height(), pointerDirection = this.pointerDirection(), pointerWidth = this.pointerWidth(), pointerHeight = this.pointerHeight(), cornerRadius = this.cornerRadius(); const [topLeft, topRight, bottomRight, bottomLeft] = Util._cornerRadii(cornerRadius, width, height); context.beginPath(); context.moveTo(topLeft, 0); if (pointerDirection === UP) { context.lineTo((width - pointerWidth) / 2, 0); context.lineTo(width / 2, -1 * pointerHeight); context.lineTo((width + pointerWidth) / 2, 0); } 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); context.lineTo(width + pointerWidth, height / 2); context.lineTo(width, (height + pointerHeight) / 2); } 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); context.lineTo(width / 2, height + pointerHeight); context.lineTo((width - pointerWidth) / 2, height); } 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); context.lineTo(-1 * pointerWidth, height / 2); context.lineTo(0, (height - pointerHeight) / 2); } context.lineTo(0, topLeft); context.arc(topLeft, topLeft, topLeft, Math.PI, (Math.PI * 3) / 2, false); context.closePath(); context.fillStrokeShape(this); } getSelfRect() { let x = 0, y = 0, pointerWidth = this.pointerWidth(), pointerHeight = this.pointerHeight(), direction = this.pointerDirection(), width = this.width(), height = this.height(); if (direction === UP) { y -= pointerHeight; height += pointerHeight; } else if (direction === DOWN) { height += pointerHeight; } else if (direction === LEFT) { x -= pointerWidth; width += pointerWidth; } else if (direction === RIGHT) { width += pointerWidth; } return { x: x, y: y, width: width, height: height, }; } } Tag.prototype.className = 'Tag'; _registerNode(Tag); /** * get/set pointer direction * @name Konva.Tag#pointerDirection * @method * @param {String} pointerDirection can be up, right, down, left, or none. The default is none. * @returns {String} * @example * tag.pointerDirection('right'); */ Factory.addGetterSetter(Tag, 'pointerDirection', NONE); /** * get/set pointer width * @name Konva.Tag#pointerWidth * @method * @param {Number} pointerWidth * @returns {Number} * @example * tag.pointerWidth(20); */ Factory.addGetterSetter(Tag, 'pointerWidth', 0, getNumberValidator()); /** * get/set pointer height * @method * @name Konva.Tag#pointerHeight * @param {Number} pointerHeight * @returns {Number} * @example * tag.pointerHeight(20); */ Factory.addGetterSetter(Tag, 'pointerHeight', 0, getNumberValidator()); /** * get/set cornerRadius * @name Konva.Tag#cornerRadius * @method * @param {Number} cornerRadius * @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, getNumberOrArrayOfNumbersValidator(4));