UNPKG

konva

Version:

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

318 lines (317 loc) 8.71 kB
import { Factory } from "../Factory.js"; import { Shape } from "../Shape.js"; import { Animation } from "../Animation.js"; import { getNumberValidator } from "../Validators.js"; import { _registerNode } from "../Global.js"; /** * Sprite constructor * @constructor * @memberof Konva * @augments Konva.Shape * @param {Object} config * @param {String} config.animation animation key * @param {Object} config.animations animation map * @param {Integer} [config.frameIndex] animation frame index * @param {Image} config.image image object * @param {Integer} [config.frameRate] animation frame rate * @@shapeParams * @@nodeParams * @example * var imageObj = new Image(); * imageObj.onload = function() { * var sprite = new Konva.Sprite({ * x: 200, * y: 100, * image: imageObj, * animation: 'standing', * animations: { * standing: [ * // x, y, width, height (6 frames) * 0, 0, 49, 109, * 52, 0, 49, 109, * 105, 0, 49, 109, * 158, 0, 49, 109, * 210, 0, 49, 109, * 262, 0, 49, 109 * ], * kicking: [ * // x, y, width, height (6 frames) * 0, 109, 45, 98, * 45, 109, 45, 98, * 95, 109, 63, 98, * 156, 109, 70, 98, * 229, 109, 60, 98, * 287, 109, 41, 98 * ] * }, * frameRate: 7, * frameIndex: 0 * }); * }; * imageObj.src = '/path/to/image.jpg' */ export class Sprite extends Shape { constructor(config) { super(config); this._updated = true; this.anim = new Animation(() => { // if we don't need to redraw layer we should return false const updated = this._updated; this._updated = false; return updated; }); this.on('animationChange.konva', function () { // reset index when animation changes this.frameIndex(0); }); this.on('frameIndexChange.konva', function () { this._updated = true; }); // smooth change for frameRate this.on('frameRateChange.konva', function () { if (!this.anim.isRunning()) { return; } clearInterval(this.interval); this._setInterval(); }); } // the current frame: its box in the sprite sheet and where it is drawn, // or nothing when the animation key or the frame index does not exist // (then nothing is drawn, like an image without an image) _getFrame() { var _a, _b; const anim = this.animation(), set = (_a = this.animations()) === null || _a === void 0 ? void 0 : _a[anim], index = this.frameIndex(), ix4 = index * 4; if (!set || !Number.isInteger(index) || ix4 < 0 || ix4 + 4 > set.length) { return; } const offset = ((_b = this.frameOffsets()) === null || _b === void 0 ? void 0 : _b[anim]) || []; return { x: set[ix4], y: set[ix4 + 1], width: set[ix4 + 2], height: set[ix4 + 3], offsetX: offset[index * 2] || 0, offsetY: offset[index * 2 + 1] || 0, }; } _sceneFunc(context) { const frame = this._getFrame(); if (!frame) { return; } const { x, y, width, height, offsetX, offsetY } = frame; const image = this.image(); if (this.hasFill() || this.hasStroke()) { context.beginPath(); context.rect(offsetX, offsetY, width, height); context.closePath(); context.fillStrokeShape(this); } if (image) { context.drawImage(image, x, y, width, height, offsetX, offsetY, width, height); } } _hitFunc(context) { const { x, y, width, height } = this.getSelfRect(); context.beginPath(); context.rect(x, y, width, height); context.closePath(); context.fillShape(this); } getSelfRect() { const frame = this._getFrame(); return frame ? { x: frame.offsetX, y: frame.offsetY, width: frame.width, height: frame.height, } : { x: 0, y: 0, width: 0, height: 0 }; } _useBufferCanvas() { return super._useBufferCanvas(true); } _setInterval() { const that = this; this.interval = setInterval(function () { that._updateIndex(); }, 1000 / this.frameRate()); } /** * start sprite animation * @method * @name Konva.Sprite#start */ start() { if (this.isRunning()) { return; } const layer = this.getLayer(); // The interval advances frames; the animation callback requests a redraw // only when a frame has changed. this.anim.setLayers(layer); this._setInterval(); this.anim.start(); } /** * stop sprite animation * @method * @name Konva.Sprite#stop */ stop() { this.anim.stop(); clearInterval(this.interval); } destroy() { this.stop(); return super.destroy(); } /** * determine if animation of sprite is running or not. returns true or false * @method * @name Konva.Sprite#isRunning * @returns {Boolean} */ isRunning() { return this.anim.isRunning(); } _updateIndex() { var _a; const index = this.frameIndex(), set = (_a = this.animations()) === null || _a === void 0 ? void 0 : _a[this.animation()], len = set ? set.length / 4 : 0; this.frameIndex(index < len - 1 ? index + 1 : 0); } } Sprite.prototype.className = 'Sprite'; _registerNode(Sprite); // add getters setters Factory.addGetterSetter(Sprite, 'animation'); /** * get/set animation key * @name Konva.Sprite#animation * @method * @param {String} anim animation key * @returns {String} * @example * // get animation key * var animation = sprite.animation(); * * // set animation key * sprite.animation('kicking'); */ Factory.addGetterSetter(Sprite, 'animations'); /** * get/set animations map * @name Konva.Sprite#animations * @method * @param {Object} animations * @returns {Object} * @example * // get animations map * var animations = sprite.animations(); * * // set animations map * sprite.animations({ * standing: [ * // x, y, width, height (6 frames) * 0, 0, 49, 109, * 52, 0, 49, 109, * 105, 0, 49, 109, * 158, 0, 49, 109, * 210, 0, 49, 109, * 262, 0, 49, 109 * ], * kicking: [ * // x, y, width, height (6 frames) * 0, 109, 45, 98, * 45, 109, 45, 98, * 95, 109, 63, 98, * 156, 109, 70, 98, * 229, 109, 60, 98, * 287, 109, 41, 98 * ] * }); */ Factory.addGetterSetter(Sprite, 'frameOffsets'); /** * get/set frame offsets map * @name Konva.Sprite#frameOffsets * @method * @param {Object} frameOffsets * @returns {Object} * @example * // get frame offsets map * var offsets = sprite.frameOffsets(); * * // set frame offsets map * sprite.frameOffsets({ * standing: [ * // x, y (6 frames) * 0, 0, * 0, 0, * 5, 0, * 0, 0, * 0, 3, * 2, 0 * ], * kicking: [ * // x, y (6 frames) * 0, 5, * 5, 0, * 10, 0, * 0, 0, * 2, 1, * 0, 0 * ] * }); */ Factory.addGetterSetter(Sprite, 'image'); /** * get/set image * @name Konva.Sprite#image * @method * @param {Image} image * @returns {Image} * @example * // get image * var image = sprite.image(); * * // set image * sprite.image(imageObj); */ Factory.addGetterSetter(Sprite, 'frameIndex', 0, getNumberValidator()); /** * set/set animation frame index * @name Konva.Sprite#frameIndex * @method * @param {Integer} frameIndex * @returns {Integer} * @example * // get animation frame index * var frameIndex = sprite.frameIndex(); * * // set animation frame index * sprite.frameIndex(3); */ Factory.addGetterSetter(Sprite, 'frameRate', 17, getNumberValidator()); /** * get/set frame rate in frames per second. Increase this number to make the sprite * animation run faster, and decrease the number to make the sprite animation run slower * The default is 17 frames per second * @name Konva.Sprite#frameRate * @method * @param {Integer} frameRate * @returns {Integer} * @example * // get frame rate * var frameRate = sprite.frameRate(); * * // set frame rate to 2 frames per second * sprite.frameRate(2); */ Factory.backCompat(Sprite, { index: 'frameIndex', getIndex: 'getFrameIndex', setIndex: 'setFrameIndex', });