X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/draw/Sprite.js diff --git a/src/draw/Sprite.js b/src/draw/Sprite.js new file mode 100644 index 00000000..de44b2b6 --- /dev/null +++ b/src/draw/Sprite.js @@ -0,0 +1,398 @@ +/** + * @class Ext.draw.Sprite + * @extends Object + * + * A Sprite is an object rendered in a Drawing surface. There are different options and types of sprites. + * The configuration of a Sprite is an object with the following properties: + * + * - **type** - (String) The type of the sprite. Possible options are 'circle', 'path', 'rect', 'text', 'square'. + * - **width** - (Number) Used in rectangle sprites, the width of the rectangle. + * - **height** - (Number) Used in rectangle sprites, the height of the rectangle. + * - **size** - (Number) Used in square sprites, the dimension of the square. + * - **radius** - (Number) Used in circle sprites, the radius of the circle. + * - **x** - (Number) The position along the x-axis. + * - **y** - (Number) The position along the y-axis. + * - **path** - (Array) Used in path sprites, the path of the sprite written in SVG-like path syntax. + * - **opacity** - (Number) The opacity of the sprite. + * - **fill** - (String) The fill color. + * - **stroke** - (String) The stroke color. + * - **stroke-width** - (Number) The width of the stroke. + * - **font** - (String) Used with text type sprites. The full font description. Uses the same syntax as the CSS `font` parameter. + * - **text** - (String) Used with text type sprites. The text itself. + * + * Additionally there are three transform objects that can be set with `setAttributes` which are `translate`, `rotate` and + * `scale`. + * + * For translate, the configuration object contains x and y attributes that indicate where to + * translate the object. For example: + * + * sprite.setAttributes({ + * translate: { + * x: 10, + * y: 10 + * } + * }, true); + * + * For rotation, the configuration object contains x and y attributes for the center of the rotation (which are optional), + * and a `degrees` attribute that specifies the rotation in degrees. For example: + * + * sprite.setAttributes({ + * rotate: { + * degrees: 90 + * } + * }, true); + * + * For scaling, the configuration object contains x and y attributes for the x-axis and y-axis scaling. For example: + * + * sprite.setAttributes({ + * scale: { + * x: 10, + * y: 3 + * } + * }, true); + * + * Sprites can be created with a reference to a {@link Ext.draw.Surface} + * + * var drawComponent = Ext.create('Ext.draw.Component', options here...); + * + * var sprite = Ext.create('Ext.draw.Sprite', { + * type: 'circle', + * fill: '#ff0', + * surface: drawComponent.surface, + * radius: 5 + * }); + * + * Sprites can also be added to the surface as a configuration object: + * + * var sprite = drawComponent.surface.add({ + * type: 'circle', + * fill: '#ff0', + * radius: 5 + * }); + * + * In order to properly apply properties and render the sprite we have to + * `show` the sprite setting the option `redraw` to `true`: + * + * sprite.show(true); + * + * The constructor configuration object of the Sprite can also be used and passed into the {@link Ext.draw.Surface} + * add method to append a new sprite to the canvas. For example: + * + * drawComponent.surface.add({ + * type: 'circle', + * fill: '#ffc', + * radius: 100, + * x: 100, + * y: 100 + * }); + */ +Ext.define('Ext.draw.Sprite', { + /* Begin Definitions */ + + mixins: { + observable: 'Ext.util.Observable', + animate: 'Ext.util.Animate' + }, + + requires: ['Ext.draw.SpriteDD'], + + /* End Definitions */ + + dirty: false, + dirtyHidden: false, + dirtyTransform: false, + dirtyPath: true, + dirtyFont: true, + zIndexDirty: true, + isSprite: true, + zIndex: 0, + fontProperties: [ + 'font', + 'font-size', + 'font-weight', + 'font-style', + 'font-family', + 'text-anchor', + 'text' + ], + pathProperties: [ + 'x', + 'y', + 'd', + 'path', + 'height', + 'width', + 'radius', + 'r', + 'rx', + 'ry', + 'cx', + 'cy' + ], + constructor: function(config) { + var me = this; + config = config || {}; + me.id = Ext.id(null, 'ext-sprite-'); + me.transformations = []; + Ext.copyTo(this, config, 'surface,group,type,draggable'); + //attribute bucket + me.bbox = {}; + me.attr = { + zIndex: 0, + translation: { + x: null, + y: null + }, + rotation: { + degrees: null, + x: null, + y: null + }, + scaling: { + x: null, + y: null, + cx: null, + cy: null + } + }; + //delete not bucket attributes + delete config.surface; + delete config.group; + delete config.type; + delete config.draggable; + me.setAttributes(config); + me.addEvents( + 'beforedestroy', + 'destroy', + 'render', + 'mousedown', + 'mouseup', + 'mouseover', + 'mouseout', + 'mousemove', + 'click' + ); + me.mixins.observable.constructor.apply(this, arguments); + }, + + /** + *

If this Sprite is configured {@link #draggable}, this property will contain + * an instance of {@link Ext.dd.DragSource} which handles dragging the Sprite.

+ * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource} + * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}. + * @type Ext.dd.DragSource. + * @property dd + */ + initDraggable: function() { + var me = this; + me.draggable = true; + //create element if it doesn't exist. + if (!me.el) { + me.surface.createSprite(me); + } + me.dd = Ext.create('Ext.draw.SpriteDD', me, Ext.isBoolean(me.draggable) ? null : me.draggable); + me.on('beforedestroy', me.dd.destroy, me.dd); + }, + + /** + * Change the attributes of the sprite. + * @param {Object} attrs attributes to be changed on the sprite. + * @param {Boolean} redraw Flag to immediatly draw the change. + * @return {Ext.draw.Sprite} this + */ + setAttributes: function(attrs, redraw) { + var me = this, + fontProps = me.fontProperties, + fontPropsLength = fontProps.length, + pathProps = me.pathProperties, + pathPropsLength = pathProps.length, + hasSurface = !!me.surface, + custom = hasSurface && me.surface.customAttributes || {}, + spriteAttrs = me.attr, + attr, i, translate, translation, rotate, rotation, scale, scaling; + + for (attr in custom) { + if (attrs.hasOwnProperty(attr) && typeof custom[attr] == "function") { + Ext.apply(attrs, custom[attr].apply(me, [].concat(attrs[attr]))); + } + } + + // Flag a change in hidden + if (!!attrs.hidden !== !!spriteAttrs.hidden) { + me.dirtyHidden = true; + } + + // Flag path change + for (i = 0; i < pathPropsLength; i++) { + attr = pathProps[i]; + if (attr in attrs && attrs[attr] !== spriteAttrs[attr]) { + me.dirtyPath = true; + break; + } + } + + // Flag zIndex change + if ('zIndex' in attrs) { + me.zIndexDirty = true; + } + + // Flag font/text change + for (i = 0; i < fontPropsLength; i++) { + attr = fontProps[i]; + if (attr in attrs && attrs[attr] !== spriteAttrs[attr]) { + me.dirtyFont = true; + break; + } + } + + translate = attrs.translate; + translation = spriteAttrs.translation; + if (translate) { + if ((translate.x && translate.x !== translation.x) || + (translate.y && translate.y !== translation.y)) { + Ext.apply(translation, translate); + me.dirtyTransform = true; + } + delete attrs.translate; + } + + rotate = attrs.rotate; + rotation = spriteAttrs.rotation; + if (rotate) { + if ((rotate.x && rotate.x !== rotation.x) || + (rotate.y && rotate.y !== rotation.y) || + (rotate.degrees && rotate.degrees !== rotation.degrees)) { + Ext.apply(rotation, rotate); + me.dirtyTransform = true; + } + delete attrs.rotate; + } + + scale = attrs.scale; + scaling = spriteAttrs.scaling; + if (scale) { + if ((scale.x && scale.x !== scaling.x) || + (scale.y && scale.y !== scaling.y) || + (scale.cx && scale.cx !== scaling.cx) || + (scale.cy && scale.cy !== scaling.cy)) { + Ext.apply(scaling, scale); + me.dirtyTransform = true; + } + delete attrs.scale; + } + + Ext.apply(spriteAttrs, attrs); + me.dirty = true; + + if (redraw === true && hasSurface) { + me.redraw(); + } + return this; + }, + + /** + * Retrieve the bounding box of the sprite. This will be returned as an object with x, y, width, and height properties. + * @return {Object} bbox + */ + getBBox: function() { + return this.surface.getBBox(this); + }, + + setText: function(text) { + return this.surface.setText(this, text); + }, + + /** + * Hide the sprite. + * @param {Boolean} redraw Flag to immediatly draw the change. + * @return {Ext.draw.Sprite} this + */ + hide: function(redraw) { + this.setAttributes({ + hidden: true + }, redraw); + return this; + }, + + /** + * Show the sprite. + * @param {Boolean} redraw Flag to immediatly draw the change. + * @return {Ext.draw.Sprite} this + */ + show: function(redraw) { + this.setAttributes({ + hidden: false + }, redraw); + return this; + }, + + /** + * Remove the sprite. + */ + remove: function() { + if (this.surface) { + this.surface.remove(this); + return true; + } + return false; + }, + + onRemove: function() { + this.surface.onRemove(this); + }, + + /** + * Removes the sprite and clears all listeners. + */ + destroy: function() { + var me = this; + if (me.fireEvent('beforedestroy', me) !== false) { + me.remove(); + me.surface.onDestroy(me); + me.clearListeners(); + me.fireEvent('destroy'); + } + }, + + /** + * Redraw the sprite. + * @return {Ext.draw.Sprite} this + */ + redraw: function() { + this.surface.renderItem(this); + return this; + }, + + /** + * Wrapper for setting style properties, also takes single object parameter of multiple styles. + * @param {String/Object} property The style property to be set, or an object of multiple styles. + * @param {String} value (optional) The value to apply to the given property, or null if an object was passed. + * @return {Ext.draw.Sprite} this + */ + setStyle: function() { + this.el.setStyle.apply(this.el, arguments); + return this; + }, + + /** + * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out. Note this method + * is severly limited in VML. + * @param {String/Array} className The CSS class to add, or an array of classes + * @return {Ext.draw.Sprite} this + */ + addCls: function(obj) { + this.surface.addCls(this, obj); + return this; + }, + + /** + * Removes one or more CSS classes from the element. + * @param {String/Array} className The CSS class to remove, or an array of classes. Note this method + * is severly limited in VML. + * @return {Ext.draw.Sprite} this + */ + removeCls: function(obj) { + this.surface.removeCls(this, obj); + return this; + } +});