var zrUtil = require("../core/util"); var Style = require("./Style"); var Element = require("../Element"); var RectText = require("./mixin/RectText"); /** * Base class of all displayable graphic objects * @module zrender/graphic/Displayable */ /** * @alias module:zrender/graphic/Displayable * @extends module:zrender/Element * @extends module:zrender/graphic/mixin/RectText */ function Displayable(opts) { opts = opts || {}; Element.call(this, opts); // Extend properties for (var name in opts) { if (opts.hasOwnProperty(name) && name !== 'style') { this[name] = opts[name]; } } /** * @type {module:zrender/graphic/Style} */ this.style = new Style(opts.style, this); this._rect = null; // Shapes for cascade clipping. // Can only be `null`/`undefined` or an non-empty array, MUST NOT be an empty array. // because it is easy to only using null to check whether clipPaths changed. this.__clipPaths = null; // FIXME Stateful must be mixined after style is setted // Stateful.call(this, opts); } Displayable.prototype = { constructor: Displayable, type: 'displayable', /** * Dirty flag. From which painter will determine if this displayable object needs brush. * @name module:zrender/graphic/Displayable#__dirty * @type {boolean} */ __dirty: true, /** * Whether the displayable object is visible. when it is true, the displayable object * is not drawn, but the mouse event can still trigger the object. * @name module:/zrender/graphic/Displayable#invisible * @type {boolean} * @default false */ invisible: false, /** * @name module:/zrender/graphic/Displayable#z * @type {number} * @default 0 */ z: 0, /** * @name module:/zrender/graphic/Displayable#z * @type {number} * @default 0 */ z2: 0, /** * The z level determines the displayable object can be drawn in which layer canvas. * @name module:/zrender/graphic/Displayable#zlevel * @type {number} * @default 0 */ zlevel: 0, /** * Whether it can be dragged. * @name module:/zrender/graphic/Displayable#draggable * @type {boolean} * @default false */ draggable: false, /** * Whether is it dragging. * @name module:/zrender/graphic/Displayable#draggable * @type {boolean} * @default false */ dragging: false, /** * Whether to respond to mouse events. * @name module:/zrender/graphic/Displayable#silent * @type {boolean} * @default false */ silent: false, /** * If enable culling * @type {boolean} * @default false */ culling: false, /** * Mouse cursor when hovered * @name module:/zrender/graphic/Displayable#cursor * @type {string} */ cursor: 'pointer', /** * If hover area is bounding rect * @name module:/zrender/graphic/Displayable#rectHover * @type {string} */ rectHover: false, /** * Render the element progressively when the value >= 0, * usefull for large data. * @type {boolean} */ progressive: false, /** * @type {boolean} */ incremental: false, /** * Scale ratio for global scale. * @type {boolean} */ globalScaleRatio: 1, beforeBrush: function (ctx) {}, afterBrush: function (ctx) {}, /** * Graphic drawing method. * @param {CanvasRenderingContext2D} ctx */ // Interface brush: function (ctx, prevEl) {}, /** * Get the minimum bounding box. * @return {module:zrender/core/BoundingRect} */ // Interface getBoundingRect: function () {}, /** * If displayable element contain coord x, y * @param {number} x * @param {number} y * @return {boolean} */ contain: function (x, y) { return this.rectContain(x, y); }, /** * @param {Function} cb * @param {} context */ traverse: function (cb, context) { cb.call(context, this); }, /** * If bounding rect of element contain coord x, y * @param {number} x * @param {number} y * @return {boolean} */ rectContain: function (x, y) { var coord = this.transformCoordToLocal(x, y); var rect = this.getBoundingRect(); return rect.contain(coord[0], coord[1]); }, /** * Mark displayable element dirty and refresh next frame */ dirty: function () { this.__dirty = this.__dirtyText = true; this._rect = null; this.__zr && this.__zr.refresh(); }, /** * If displayable object binded any event * @return {boolean} */ // TODO, events bound by bind // isSilent: function () { // return !( // this.hoverable || this.draggable // || this.onmousemove || this.onmouseover || this.onmouseout // || this.onmousedown || this.onmouseup || this.onclick // || this.ondragenter || this.ondragover || this.ondragleave // || this.ondrop // ); // }, /** * Alias for animate('style') * @param {boolean} loop */ animateStyle: function (loop) { return this.animate('style', loop); }, attrKV: function (key, value) { if (key !== 'style') { Element.prototype.attrKV.call(this, key, value); } else { this.style.set(value); } }, /** * @param {Object|string} key * @param {*} value */ setStyle: function (key, value) { this.style.set(key, value); this.dirty(false); return this; }, /** * Use given style object * @param {Object} obj */ useStyle: function (obj) { this.style = new Style(obj, this); this.dirty(false); return this; }, /** * The string value of `textPosition` needs to be calculated to a real postion. * For example, `'inside'` is calculated to `[rect.width/2, rect.height/2]` * by default. See `contain/text.js#calculateTextPosition` for more details. * But some coutom shapes like "pin", "flag" have center that is not exactly * `[width/2, height/2]`. So we provide this hook to customize the calculation * for those shapes. It will be called if the `style.textPosition` is a string. * @param {Obejct} [out] Prepared out object. If not provided, this method should * be responsible for creating one. * @param {module:zrender/graphic/Style} style * @param {Object} rect {x, y, width, height} * @return {Obejct} out The same as the input out. * { * x: number. mandatory. * y: number. mandatory. * textAlign: string. optional. use style.textAlign by default. * textVerticalAlign: string. optional. use style.textVerticalAlign by default. * } */ calculateTextPosition: null }; zrUtil.inherits(Displayable, Element); zrUtil.mixin(Displayable, RectText); // zrUtil.mixin(Displayable, Stateful); var _default = Displayable; module.exports = _default;