]>
git.proxmox.com Git - sencha-touch.git/blob - src/src/draw/sprite/Sprite.js
2 * A sprite is an object rendered in a drawing {@link Ext.draw.Surface}.
3 * The Sprite class itself is an abstract class and is not meant to be used directly.
4 * Every sprite in the Draw and Chart packages is a subclass of the Ext.draw.sprite.Sprite.
5 * The standard Sprite subclasses are:
7 * * {@link Ext.draw.sprite.Path} - A sprite that represents a path.
8 * * {@link Ext.draw.sprite.Rect} - A sprite that represents a rectangle.
9 * * {@link Ext.draw.sprite.Circle} - A sprite that represents a circle.
10 * * {@link Ext.draw.sprite.Sector} - A sprite representing a pie slice.
11 * * {@link Ext.draw.sprite.Arc} - A sprite that represents a circular arc.
12 * * {@link Ext.draw.sprite.Ellipse} - A sprite that represents an ellipse.
13 * * {@link Ext.draw.sprite.EllipticalArc} - A sprite that represents an elliptical arc.
14 * * {@link Ext.draw.sprite.Text} - A sprite that represents text.
15 * * {@link Ext.draw.sprite.Image} - A sprite that represents an image.
16 * * {@link Ext.draw.sprite.Instancing} - A sprite that represents multiple instances based on the given template.
17 * * {@link Ext.draw.sprite.Composite} - Represents a group of sprites.
19 * Sprites can be created with a reference to a {@link Ext.draw.Surface}
21 * var drawComponent = Ext.create('Ext.draw.Component', {
25 * var sprite = Ext.create('Ext.draw.sprite.Sprite', {
28 * surface: drawComponent.getSurface('main'),
32 * Sprites can also be added to the surface as a configuration object:
34 * var sprite = drawComponent.getSurface('main').add({
40 Ext
.define('Ext.draw.sprite.Sprite', {
41 alias
: 'sprite.sprite',
44 observable
: 'Ext.mixin.Observable'
49 'Ext.draw.gradient.Gradient',
50 'Ext.draw.sprite.AttributeDefinition',
51 'Ext.draw.sprite.AttributeParser',
52 'Ext.draw.modifier.Target',
53 'Ext.draw.modifier.Animation',
54 'Ext.draw.modifier.Highlight'
63 * @cfg {String} [strokeStyle="none"] The color of the stroke (a CSS color value).
68 * @cfg {String} [fillStyle="none"] The color of the shape (a CSS color value).
73 * @cfg {Number} [strokeOpacity=1] The opacity of the stroke. Limited from 0 to 1.
75 strokeOpacity
: "limited01",
78 * @cfg {Number} [fillOpacity=1] The opacity of the fill. Limited from 0 to 1.
80 fillOpacity
: "limited01",
83 * @cfg {Number} [lineWidth=1] The width of the line stroke.
88 * @cfg {String} [lineCap="butt"] The style of the line caps.
90 lineCap
: "enums(butt,round,square)",
93 * @cfg {String} [lineJoin="miter"] The style of the line join.
95 lineJoin
: "enums(round,bevel,miter)",
98 * @cfg {Array} An array of non-negative numbers specifying a dash/space sequence.
103 * @cfg {Number} A number specifying how far into the line dash sequence drawing commences.
105 lineDashOffset
: "number",
108 * @cfg {Number} [miterLimit=1] Sets the distance between the inner corner and the outer corner where two lines meet.
110 miterLimit
: "number",
113 * @cfg {String} [shadowColor="none"] The color of the shadow (a CSS color value).
115 shadowColor
: "color",
118 * @cfg {Number} [shadowOffsetX=0] The offset of the sprite's shadow on the x-axis.
120 shadowOffsetX
: "number",
123 * @cfg {Number} [shadowOffsetY=0] The offset of the sprite's shadow on the y-axis.
125 shadowOffsetY
: "number",
128 * @cfg {Number} [shadowBlur=0] The amount blur used on the shadow.
130 shadowBlur
: "number",
133 * @cfg {Number} [globalAlpha=1] The opacity of the sprite. Limited from 0 to 1.
135 globalAlpha
: "limited01",
136 globalCompositeOperation
: "enums(source-over,destination-over,source-in,destination-in,source-out,destination-out,source-atop,destination-atop,lighter,xor,copy)",
139 * @cfg {Boolean} [hidden=false] Determines whether or not the sprite is hidden.
144 * @cfg {Boolean} [transformFillStroke=false] Determines whether the fill and stroke are affected by sprite transformations.
146 transformFillStroke
: "bool",
149 * @cfg {Number} [zIndex=0] The stacking order of the sprite.
154 * @cfg {Number} [translationX=0] The translation of the sprite on the x-axis.
156 translationX
: "number",
159 * @cfg {Number} [translationY=0] The translation of the sprite on the y-axis.
161 translationY
: "number",
164 * @cfg {Number} [rotationRads=0] The degree of rotation of the sprite.
166 rotationRads
: "number",
169 * @cfg {Number} [rotationCenterX=null] The central coordinate of the sprite's scale operation on the x-axis.
171 rotationCenterX
: "number",
174 * @cfg {Number} [rotationCenterY=null] The central coordinate of the sprite's rotate operation on the y-axis.
176 rotationCenterY
: "number",
179 * @cfg {Number} [scalingX=1] The scaling of the sprite on the x-axis.
184 * @cfg {Number} [scalingY=1] The scaling of the sprite on the y-axis.
189 * @cfg {Number} [scalingCenterX=null] The central coordinate of the sprite's scale operation on the x-axis.
191 scalingCenterX
: "number",
194 * @cfg {Number} [scalingCenterY=null] The central coordinate of the sprite's scale operation on the y-axis.
196 scalingCenterY
: "number",
198 constrainGradients
: "bool"
202 "stroke": "strokeStyle",
204 "color": "fillStyle",
205 "stroke-width": "lineWidth",
206 "stroke-linecap": "lineCap",
207 "stroke-linejoin": "lineJoin",
208 "stroke-miterlimit": "miterLimit",
209 "text-anchor": "textAlign",
210 "opacity": "globalAlpha",
212 translateX
: "translationX",
213 translateY
: "translationY",
214 rotateRads
: "rotationRads",
215 rotateCenterX
: "rotationCenterX",
216 rotateCenterY
: "rotationCenterY",
219 scaleCenterX
: "scalingCenterX",
220 scaleCenterY
: "scalingCenterY"
244 transformFillStroke
: false,
249 rotationCenterX
: null,
250 rotationCenterY
: null,
253 scalingCenterX
: null,
254 scalingCenterY
: null,
256 constrainGradients
: false
263 globalAlpha
: "canvas",
264 globalCompositeOperation
: "canvas",
266 transformFillStroke
: "canvas",
267 strokeStyle
: "canvas",
269 strokeOpacity
: "canvas",
270 fillOpacity
: "canvas",
276 lineDashOffset
: "canvas",
277 miterLimit
: "canvas",
279 shadowColor
: "canvas",
280 shadowOffsetX
: "canvas",
281 shadowOffsetY
: "canvas",
282 shadowBlur
: "canvas",
284 translationX
: "transform",
285 translationY
: "transform",
286 rotationRads
: "transform",
287 rotationCenterX
: "transform",
288 rotationCenterY
: "transform",
289 scalingX
: "transform",
290 scalingY
: "transform",
291 scalingCenterX
: "transform",
292 scalingCenterY
: "transform",
294 constrainGradients
: "canvas"
298 "bbox": function (attrs
) {
299 attrs
.bbox
.plain
.dirty
= true;
300 attrs
.bbox
.transform
.dirty
= true;
302 attrs
.rotationRads
!== 0 && (attrs
.rotationCenterX
=== null || attrs
.rotationCenterY
=== null) ||
303 ((attrs
.scalingX
!== 1 || attrs
.scalingY
!== 1) &&
304 (attrs
.scalingCenterX
=== null || attrs
.scalingCenterY
=== null)
307 if (!attrs
.dirtyFlags
.transform
) {
308 attrs
.dirtyFlags
.transform
= [];
313 "zIndex": function (attrs
) {
314 attrs
.dirtyZIndex
= true;
317 "transform": function (attrs
) {
318 attrs
.dirtyTransform
= true;
319 attrs
.bbox
.transform
.dirty
= true;
326 * @property {Object} attr
327 * The visual attributes of the sprite, e.g. strokeStyle, fillStyle, lineWidth...
335 onClassExtended: function (Class
, member
) {
336 var initCfg
= Class
.superclass
.self
.def
.initialConfig
,
339 if (member
.inheritableStatics
&& member
.inheritableStatics
.def
) {
340 cfg
= Ext
.merge({}, initCfg
, member
.inheritableStatics
.def
);
341 Class
.def
= Ext
.create("Ext.draw.sprite.AttributeDefinition", cfg
);
342 delete member
.inheritableStatics
.def
;
344 Class
.def
= Ext
.create("Ext.draw.sprite.AttributeDefinition", initCfg
);
348 constructor: function (config
) {
349 if (this.$className
=== 'Ext.draw.sprite.Sprite') {
350 throw 'Ext.draw.sprite.Sprite is an abstract class';
352 config
= config
|| {};
355 me
.id
= config
.id
|| Ext
.id(null, 'ext-sprite-');
357 me
.initConfig(config
);
358 var modifiers
= Ext
.Array
.from(config
.modifiers
, true);
359 me
.prepareModifiers(modifiers
);
360 me
.initializeAttributes();
361 me
.setAttributes(me
.self
.def
.getDefaults(), true);
362 me
.setAttributes(config
);
365 getDirty: function () {
366 return this.attr
.dirty
;
369 setDirty: function (dirty
) {
370 if ((this.attr
.dirty
= dirty
)) {
372 this._parent
.setDirty(true);
377 addModifier: function (modifier
, reinitializeAttributes
) {
379 if (!(modifier
instanceof Ext
.draw
.modifier
.Modifier
)) {
380 modifier
= Ext
.factory(modifier
, null, null, 'modifier');
382 modifier
.setSprite(this);
383 if (modifier
.preFx
|| modifier
.config
&& modifier
.config
.preFx
) {
384 if (me
.fx
.getPrevious()) {
385 me
.fx
.getPrevious().setNext(modifier
);
387 modifier
.setNext(me
.fx
);
389 me
.topModifier
.getPrevious().setNext(modifier
);
390 modifier
.setNext(me
.topModifier
);
392 if (reinitializeAttributes
) {
393 me
.initializeAttributes();
398 prepareModifiers: function (additionalModifiers
) {
403 me
.topModifier
= new Ext
.draw
.modifier
.Target({sprite
: me
});
406 me
.fx
= new Ext
.draw
.modifier
.Animation({sprite
: me
});
407 me
.fx
.setNext(me
.topModifier
);
409 for (i
= 0, ln
= additionalModifiers
.length
; i
< ln
; i
++) {
410 me
.addModifier(additionalModifiers
[i
], false);
414 initializeAttributes: function () {
416 me
.topModifier
.prepareAttributes(me
.attr
);
419 updateDirtyFlags: function (attrs
) {
421 dirtyFlags
= attrs
.dirtyFlags
, flags
,
422 updaters
= me
.self
.def
._updaters
,
429 for (flag
in dirtyFlags
) {
430 me
.updateDirtyFlags
= Ext
.emptyFn
;
431 flags
= dirtyFlags
[flag
];
432 delete dirtyFlags
[flag
];
433 if (updaters
[flag
]) {
434 updaters
[flag
].call(me
, attrs
, flags
);
437 delete me
.updateDirtyFlags
;
439 dirty
= dirty
|| any
;
448 * Set attributes of the sprite.
450 * @param {Object} changes The content of the change.
451 * @param {Boolean} [bypassNormalization] `true` to avoid normalization of the given changes.
452 * @param {Boolean} [avoidCopy] `true` to avoid copying the `changes` object.
453 * The content of object may be destroyed.
455 setAttributes: function (changes
, bypassNormalization
, avoidCopy
) {
456 var attributes
= this.attr
;
457 if (bypassNormalization
) {
459 this.topModifier
.pushDown(attributes
, changes
);
461 this.topModifier
.pushDown(attributes
, Ext
.apply({}, changes
));
464 this.topModifier
.pushDown(attributes
, this.self
.def
.normalize(changes
));
469 * Set attributes of the sprite, assuming the names and values have already been
472 * @deprecated Use setAttributes directy with bypassNormalization argument being `true`.
473 * @param {Object} changes The content of the change.
474 * @param {Boolean} [avoidCopy] `true` to avoid copying the `changes` object.
475 * The content of object may be destroyed.
477 setAttributesBypassingNormalization: function (changes
, avoidCopy
) {
478 return this.setAttributes(changes
, true, avoidCopy
);
482 * Returns the bounding box for the given Sprite as calculated with the Canvas engine.
484 * @param {Boolean} [isWithoutTransform] Whether to calculate the bounding box with the current transforms or not.
486 getBBox: function (isWithoutTransform
) {
491 transform
= bbox
.transform
;
493 me
.updatePlainBBox(plain
);
496 if (isWithoutTransform
) {
499 me
.applyTransformations();
500 if (transform
.dirty
) {
501 me
.updateTransformedBBox(transform
, plain
);
502 transform
.dirty
= false;
510 * Subclass will fill the plain object with `x`, `y`, `width`, `height` information of the plain bounding box of
513 * @param {Object} plain Target object.
515 updatePlainBBox
: Ext
.emptyFn
,
519 * Subclass will fill the plain object with `x`, `y`, `width`, `height` information of the transformed
520 * bounding box of this sprite.
522 * @param {Object} transform Target object.
523 * @param {Object} plain Auxiliary object providing information of plain object.
525 updateTransformedBBox: function (transform
, plain
) {
526 this.attr
.matrix
.transformBBox(plain
, 0, transform
);
530 * Subclass can rewrite this function to gain better performance.
531 * @param {Boolean} isWithoutTransform
534 getBBoxCenter: function (isWithoutTransform
) {
535 var bbox
= this.getBBox(isWithoutTransform
);
538 bbox
.x
+ bbox
.width
* 0.5,
539 bbox
.y
+ bbox
.height
* 0.5
548 * @return {Ext.draw.sprite.Sprite} this
552 this.attr
.hidden
= true;
559 * @return {Ext.draw.sprite.Sprite} this
563 this.attr
.hidden
= false;
569 * Applies sprite's attributes to the given context.
570 * @param {Object} ctx Context to apply sprite's attributes to.
571 * @param {Array} region The region of the context to be affected by gradients.
573 useAttributes: function (ctx
, region
) {
574 this.applyTransformations();
575 var attrs
= this.attr
,
576 canvasAttributes
= attrs
.canvasAttributes
,
577 strokeStyle
= canvasAttributes
.strokeStyle
,
578 fillStyle
= canvasAttributes
.fillStyle
,
579 lineDash
= canvasAttributes
.lineDash
,
580 lineDashOffset
= canvasAttributes
.lineDashOffset
,
584 if (strokeStyle
.isGradient
) {
585 ctx
.strokeStyle
= 'black';
586 ctx
.strokeGradient
= strokeStyle
;
588 ctx
.strokeGradient
= false;
593 if (fillStyle
.isGradient
) {
594 ctx
.fillStyle
= 'black';
595 ctx
.fillGradient
= fillStyle
;
597 ctx
.fillGradient
= false;
601 if (lineDash
&& ctx
.setLineDash
) {
602 ctx
.setLineDash(lineDash
);
605 if (lineDashOffset
&& typeof ctx
.lineDashOffset
=== 'number') {
606 ctx
.lineDashOffset
= lineDashOffset
;
609 for (id
in canvasAttributes
) {
610 if (canvasAttributes
[id
] !== undefined && canvasAttributes
[id
] !== ctx
[id
]) {
611 ctx
[id
] = canvasAttributes
[id
];
615 if(attrs
.constrainGradients
) {
616 ctx
.setGradientBBox({x
: region
[0], y
: region
[1], width
: region
[2], height
: region
[3]});
618 ctx
.setGradientBBox(this.getBBox(attrs
.transformFillStroke
));
625 * Calculates forward and inverse transform matrices.
626 * @param {Boolean} force Forces recalculation of transform matrices even when sprite's transform attributes supposedly haven't changed.
628 applyTransformations: function (force
) {
629 if (!force
&& !this.attr
.dirtyTransform
) {
634 center
= me
.getBBoxCenter(true),
638 x
= attr
.translationX
,
639 y
= attr
.translationY
,
642 sy
= attr
.scalingY
=== null ? attr
.scalingX
: attr
.scalingY
,
643 scx
= attr
.scalingCenterX
=== null ? centerX
: attr
.scalingCenterX
,
644 scy
= attr
.scalingCenterY
=== null ? centerY
: attr
.scalingCenterY
,
646 rad
= attr
.rotationRads
,
647 rcx
= attr
.rotationCenterX
=== null ? centerX
: attr
.rotationCenterX
,
648 rcy
= attr
.rotationCenterY
=== null ? centerY
: attr
.rotationCenterY
,
653 if (sx
=== 1 && sy
=== 1) {
663 attr
.matrix
.elements
= [
666 scx
+ (rcx
- cos
* rcx
- scx
+ rcy
* sin
) * sx
+ x
,
667 scy
+ (rcy
- cos
* rcy
- scy
+ rcx
* -sin
) * sy
+ y
669 attr
.matrix
.inverse(attr
.inverseMatrix
);
670 attr
.dirtyTransform
= false;
671 attr
.bbox
.transform
.dirty
= true;
675 * Called before rendering.
677 preRender
: Ext
.emptyFn
,
681 * @param {Ext.draw.Surface} surface The surface.
682 * @param {Object} ctx A context object compatible with CanvasRenderingContext2D.
683 * @param {Array} region The clip region (or called dirty rect) of the current rendering. Not be confused
684 * with `surface.getRegion()`.
686 * @return {*} returns `false` to stop rendering in this frame. All the sprite haven't been rendered
687 * will have their dirty flag untouched.
691 repaint: function () {
692 var parent
= this.getParent();
693 while (parent
&& !(parent
instanceof Ext
.draw
.Surface
)) {
694 parent
= parent
.getParent();
697 parent
.renderFrame();
702 * Removes the sprite and clears all listeners.
704 destroy: function () {
705 var me
= this, modifier
= me
.topModifier
, curr
;
708 modifier
= modifier
.getPrevious();
713 me
.destroy
= Ext
.emptyFn
;
714 if (me
.fireEvent('beforedestroy', me
) !== false) {
715 me
.fireEvent('destroy', me
);
720 this.def
= Ext
.create("Ext.draw.sprite.AttributeDefinition", this.def
);