]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * A Surface is an interface to render methods inside a draw {@link Ext.draw.Container}.\r | |
3 | * A Surface contains methods to render sprites, get bounding boxes of sprites, add\r | |
4 | * sprites to the canvas, initialize other graphic components, etc. One of the most used\r | |
5 | * methods for this class is the `add` method, to add Sprites to the surface.\r | |
6 | *\r | |
7 | * Most of the Surface methods are abstract and they have a concrete implementation\r | |
8 | * in Canvas or SVG engines.\r | |
9 | *\r | |
10 | * A Surface instance can be accessed as a property of a draw container. For example:\r | |
11 | *\r | |
12 | * drawContainer.getSurface('main').add({\r | |
13 | * type: 'circle',\r | |
14 | * fill: '#ffc',\r | |
15 | * radius: 100,\r | |
16 | * x: 100,\r | |
17 | * y: 100\r | |
18 | * });\r | |
19 | * drawContainer.renderFrame();\r | |
20 | *\r | |
21 | * The configuration object passed in the `add` method is the same as described in the {@link Ext.draw.sprite.Sprite}\r | |
22 | * class documentation.\r | |
23 | *\r | |
24 | * ## Example\r | |
25 | *\r | |
26 | * drawContainer.getSurface('main').add([\r | |
27 | * {\r | |
28 | * type: 'circle',\r | |
29 | * radius: 10,\r | |
30 | * fill: '#f00',\r | |
31 | * x: 10,\r | |
32 | * y: 10\r | |
33 | * },\r | |
34 | * {\r | |
35 | * type: 'circle',\r | |
36 | * radius: 10,\r | |
37 | * fill: '#0f0',\r | |
38 | * x: 50,\r | |
39 | * y: 50\r | |
40 | * },\r | |
41 | * {\r | |
42 | * type: 'circle',\r | |
43 | * radius: 10,\r | |
44 | * fill: '#00f',\r | |
45 | * x: 100,\r | |
46 | * y: 100\r | |
47 | * },\r | |
48 | * {\r | |
49 | * type: 'rect',\r | |
50 | * radius: 10,\r | |
51 | * x: 10,\r | |
52 | * y: 10\r | |
53 | * },\r | |
54 | * {\r | |
55 | * type: 'rect',\r | |
56 | * radius: 10,\r | |
57 | * x: 50,\r | |
58 | * y: 50\r | |
59 | * },\r | |
60 | * {\r | |
61 | * type: 'rect',\r | |
62 | * radius: 10,\r | |
63 | * x: 100,\r | |
64 | * y: 100\r | |
65 | * }\r | |
66 | * ]);\r | |
67 | * drawContainer.renderFrame();\r | |
68 | *\r | |
69 | */\r | |
70 | Ext.define('Ext.draw.Surface', {\r | |
71 | extend: 'Ext.draw.SurfaceBase',\r | |
72 | xtype: 'surface',\r | |
73 | \r | |
74 | requires: [\r | |
75 | 'Ext.draw.sprite.*',\r | |
76 | 'Ext.draw.gradient.*',\r | |
77 | 'Ext.draw.sprite.AttributeDefinition',\r | |
78 | 'Ext.draw.Matrix',\r | |
79 | 'Ext.draw.Draw'\r | |
80 | ],\r | |
81 | \r | |
82 | uses: [\r | |
83 | 'Ext.draw.engine.Canvas'\r | |
84 | ],\r | |
85 | \r | |
86 | /**\r | |
87 | * The reported device pixel density.\r | |
88 | * devicePixelRatio is only supported from IE11,\r | |
89 | * so we use deviceXDPI and logicalXDPI that are supported from IE6.\r | |
90 | */\r | |
91 | devicePixelRatio: window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI,\r | |
92 | \r | |
93 | deprecated: {\r | |
94 | '5.1.0': {\r | |
95 | statics: {\r | |
96 | methods: {\r | |
97 | /**\r | |
98 | * @deprecated 5.1.0\r | |
99 | * Stably sort the list of sprites by their zIndex.\r | |
100 | * Deprecated, use the {@link Ext.Array#sort} method instead.\r | |
101 | * @param {Array} list\r | |
102 | * @return {Array} Sorted array.\r | |
103 | */\r | |
104 | stableSort: function (list) {\r | |
105 | return Ext.Array.sort(list, function (a, b) {\r | |
106 | return a.attr.zIndex - b.attr.zIndex;\r | |
107 | });\r | |
108 | }\r | |
109 | }\r | |
110 | }\r | |
111 | }\r | |
112 | },\r | |
113 | \r | |
114 | config: {\r | |
115 | cls: Ext.baseCSSPrefix + 'surface',\r | |
116 | /**\r | |
117 | * @cfg {Array}\r | |
118 | * The [x, y, width, height] rect of the surface related to its container.\r | |
119 | */\r | |
120 | rect: null,\r | |
121 | \r | |
122 | /**\r | |
123 | * @cfg {Object}\r | |
124 | * Background sprite config of the surface.\r | |
125 | */\r | |
126 | background: null,\r | |
127 | \r | |
128 | /**\r | |
129 | * @cfg {Array}\r | |
130 | * Array of sprite instances.\r | |
131 | */\r | |
132 | items: [],\r | |
133 | \r | |
134 | /**\r | |
135 | * @cfg {Boolean}\r | |
136 | * Indicates whether the surface needs to redraw.\r | |
137 | */\r | |
138 | dirty: false,\r | |
139 | \r | |
140 | /**\r | |
141 | * @cfg {Boolean} flipRtlText\r | |
142 | * If the surface is in the RTL mode, text will render with the RTL direction,\r | |
143 | * but the alignment and position of the text won't change by default.\r | |
144 | * Setting this config to 'true' will get text alignment and its position\r | |
145 | * within a surface mirrored.\r | |
146 | */\r | |
147 | flipRtlText: false\r | |
148 | },\r | |
149 | \r | |
150 | isSurface: true,\r | |
151 | \r | |
152 | /**\r | |
153 | * @private\r | |
154 | * This flag is used to indicate that `predecessors` surfaces that should render\r | |
155 | * before this surface renders are dirty, and to call `renderFrame`\r | |
156 | * when all `predecessors` have their `renderFrame` called (i.e. not dirty anymore).\r | |
157 | * This flag indicates that current surface has surfaces that are yet to render\r | |
158 | * before current surface can render. When all the `predecessors` surfaces\r | |
159 | * have rendered, i.e. when `dirtyPredecessorCount` reaches zero,\r | |
160 | */\r | |
161 | isPendingRenderFrame: false,\r | |
162 | \r | |
163 | dirtyPredecessorCount: 0,\r | |
164 | \r | |
165 | constructor: function (config) {\r | |
166 | var me = this;\r | |
167 | \r | |
168 | me.predecessors = [];\r | |
169 | me.successors = [];\r | |
170 | me.map = {};\r | |
171 | \r | |
172 | me.callParent([config]);\r | |
173 | me.matrix = new Ext.draw.Matrix();\r | |
174 | me.inverseMatrix = me.matrix.inverse();\r | |
175 | },\r | |
176 | \r | |
177 | /**\r | |
178 | * Round the number to align to the pixels on device.\r | |
179 | * @param {Number} num The number to align.\r | |
180 | * @return {Number} The resultant alignment.\r | |
181 | */\r | |
182 | roundPixel: function (num) {\r | |
183 | return Math.round(this.devicePixelRatio * num) / this.devicePixelRatio;\r | |
184 | },\r | |
185 | \r | |
186 | /**\r | |
187 | * Mark the surface to render after another surface is updated.\r | |
188 | * @param {Ext.draw.Surface} surface The surface to wait for.\r | |
189 | */\r | |
190 | waitFor: function (surface) {\r | |
191 | var me = this,\r | |
192 | predecessors = me.predecessors;\r | |
193 | \r | |
194 | if (!Ext.Array.contains(predecessors, surface)) {\r | |
195 | predecessors.push(surface);\r | |
196 | surface.successors.push(me);\r | |
197 | if (surface.getDirty()) {\r | |
198 | me.dirtyPredecessorCount++;\r | |
199 | }\r | |
200 | }\r | |
201 | },\r | |
202 | \r | |
203 | updateDirty: function (dirty) {\r | |
204 | var successors = this.successors,\r | |
205 | ln = successors.length,\r | |
206 | i = 0,\r | |
207 | successor;\r | |
208 | \r | |
209 | for (; i < ln; i++) {\r | |
210 | successor = successors[i];\r | |
211 | if (dirty) {\r | |
212 | successor.dirtyPredecessorCount++;\r | |
213 | successor.setDirty(true);\r | |
214 | } else {\r | |
215 | successor.dirtyPredecessorCount--;\r | |
216 | // Don't need to call `setDirty(false)` on a successor here,\r | |
217 | // as this will be done by `renderFrame`.\r | |
218 | if (successor.dirtyPredecessorCount === 0 && successor.isPendingRenderFrame) {\r | |
219 | successor.renderFrame();\r | |
220 | }\r | |
221 | }\r | |
222 | }\r | |
223 | },\r | |
224 | \r | |
225 | applyBackground: function (background, oldBackground) {\r | |
226 | this.setDirty(true);\r | |
227 | if (Ext.isString(background)) {\r | |
228 | background = { fillStyle: background };\r | |
229 | }\r | |
230 | return Ext.factory(background, Ext.draw.sprite.Rect, oldBackground);\r | |
231 | },\r | |
232 | \r | |
233 | applyRect: function (rect, oldRect) {\r | |
234 | if (oldRect && rect[0] === oldRect[0] && rect[1] === oldRect[1] && rect[2] === oldRect[2] && rect[3] === oldRect[3]) {\r | |
235 | return;\r | |
236 | }\r | |
237 | if (Ext.isArray(rect)) {\r | |
238 | return [rect[0], rect[1], rect[2], rect[3]];\r | |
239 | } else if (Ext.isObject(rect)) {\r | |
240 | return [\r | |
241 | rect.x || rect.left,\r | |
242 | rect.y || rect.top,\r | |
243 | rect.width || (rect.right - rect.left),\r | |
244 | rect.height || (rect.bottom - rect.top)\r | |
245 | ];\r | |
246 | }\r | |
247 | },\r | |
248 | \r | |
249 | updateRect: function (rect) {\r | |
250 | var me = this,\r | |
251 | l = rect[0],\r | |
252 | t = rect[1],\r | |
253 | r = l + rect[2],\r | |
254 | b = t + rect[3],\r | |
255 | background = me.getBackground(),\r | |
256 | element = me.element;\r | |
257 | \r | |
258 | element.setLocalXY(Math.floor(l), Math.floor(t));\r | |
259 | element.setSize(Math.ceil(r - Math.floor(l)), Math.ceil(b - Math.floor(t)));\r | |
260 | \r | |
261 | if (background) {\r | |
262 | background.setAttributes({\r | |
263 | x: 0,\r | |
264 | y: 0,\r | |
265 | width: Math.ceil(r - Math.floor(l)),\r | |
266 | height: Math.ceil(b - Math.floor(t))\r | |
267 | });\r | |
268 | }\r | |
269 | me.setDirty(true);\r | |
270 | },\r | |
271 | \r | |
272 | /**\r | |
273 | * Reset the matrix of the surface.\r | |
274 | */\r | |
275 | resetTransform: function () {\r | |
276 | this.matrix.set(1, 0, 0, 1, 0, 0);\r | |
277 | this.inverseMatrix.set(1, 0, 0, 1, 0, 0);\r | |
278 | this.setDirty(true);\r | |
279 | },\r | |
280 | \r | |
281 | /**\r | |
282 | * Get the sprite by id or index.\r | |
283 | * It will first try to find a sprite with the given id, otherwise will try to use the id as an index.\r | |
284 | * @param {String|Number} id\r | |
285 | * @return {Ext.draw.sprite.Sprite}\r | |
286 | */\r | |
287 | get: function (id) {\r | |
288 | return this.map[id] || this.getItems()[id];\r | |
289 | },\r | |
290 | \r | |
291 | /**\r | |
292 | * @method\r | |
293 | * Add a Sprite to the surface.\r | |
294 | * You can put any number of objects as the parameter.\r | |
295 | * See {@link Ext.draw.sprite.Sprite} for the configuration object to be passed into this method.\r | |
296 | *\r | |
297 | * For example:\r | |
298 | *\r | |
299 | * drawContainer.getSurface().add({\r | |
300 | * type: 'circle',\r | |
301 | * fill: '#ffc',\r | |
302 | * radius: 100,\r | |
303 | * x: 100,\r | |
304 | * y: 100\r | |
305 | * });\r | |
306 | * drawContainer.renderFrame();\r | |
307 | *\r | |
308 | * @param {Object/Object[]} sprite\r | |
309 | * @returns {Ext.draw.sprite.Sprite/Ext.draw.sprite.Sprite[]}\r | |
310 | *\r | |
311 | */\r | |
312 | add: function () {\r | |
313 | var me = this,\r | |
314 | args = Array.prototype.slice.call(arguments),\r | |
315 | argIsArray = Ext.isArray(args[0]),\r | |
316 | map = me.map,\r | |
317 | results = [],\r | |
318 | items, item, sprite,\r | |
319 | i, ln;\r | |
320 | \r | |
321 | items = Ext.Array.clean(argIsArray ? args[0] : args);\r | |
322 | \r | |
323 | if (!items.length) {\r | |
324 | return results;\r | |
325 | }\r | |
326 | \r | |
327 | for (i = 0, ln = items.length; i < ln; i++) {\r | |
328 | item = items[i];\r | |
329 | sprite = null;\r | |
330 | if (item.isSprite && !map[item.getId()]) {\r | |
331 | sprite = item;\r | |
332 | } else if (!map[item.id]) {\r | |
333 | sprite = this.createItem(item);\r | |
334 | }\r | |
335 | if (sprite) {\r | |
336 | map[sprite.getId()] = sprite;\r | |
337 | results.push(sprite);\r | |
338 | sprite.setParent(me);\r | |
339 | sprite.setSurface(me);\r | |
340 | me.onAdd(sprite);\r | |
341 | }\r | |
342 | }\r | |
343 | \r | |
344 | items = me.getItems();\r | |
345 | if (items) {\r | |
346 | items.push.apply(items, results);\r | |
347 | }\r | |
348 | \r | |
349 | me.dirtyZIndex = true;\r | |
350 | me.setDirty(true);\r | |
351 | \r | |
352 | if (!argIsArray && results.length === 1) {\r | |
353 | return results[0];\r | |
354 | } else {\r | |
355 | return results;\r | |
356 | }\r | |
357 | },\r | |
358 | \r | |
359 | /**\r | |
360 | * @method\r | |
361 | * @protected\r | |
362 | * Invoked when a sprite is added to the surface.\r | |
363 | * @param {Ext.draw.sprite.Sprite} sprite The sprite to be added.\r | |
364 | */\r | |
365 | onAdd: Ext.emptyFn,\r | |
366 | \r | |
367 | /**\r | |
368 | * Remove a given sprite from the surface,\r | |
369 | * optionally destroying the sprite in the process.\r | |
370 | * You can also call the sprite's own `remove` method.\r | |
371 | *\r | |
372 | * For example:\r | |
373 | *\r | |
374 | * drawContainer.surface.remove(sprite);\r | |
375 | * // or...\r | |
376 | * sprite.remove();\r | |
377 | *\r | |
378 | * @param {Ext.draw.sprite.Sprite/String} sprite A sprite instance or its ID.\r | |
379 | * @param {Boolean} [isDestroy=false] If `true`, the sprite will be destroyed.\r | |
380 | * @returns {Ext.draw.sprite.Sprite} Returns the removed/destroyed sprite or `null` otherwise.\r | |
381 | */\r | |
382 | remove: function (sprite, isDestroy) {\r | |
383 | var me = this,\r | |
384 | id, isOwnSprite;\r | |
385 | \r | |
386 | if (sprite) {\r | |
387 | if (sprite.charAt) { // is String\r | |
388 | sprite = me.map[sprite];\r | |
389 | }\r | |
390 | if (!sprite || !sprite.isSprite) {\r | |
391 | return null;\r | |
392 | }\r | |
393 | if (sprite.isDestroyed || sprite.isDestroying) {\r | |
394 | return sprite;\r | |
395 | }\r | |
396 | id = sprite.getId();\r | |
397 | isOwnSprite = me.map[id];\r | |
398 | delete me.map[id];\r | |
399 | \r | |
400 | if (isDestroy) {\r | |
401 | sprite.destroy();\r | |
402 | }\r | |
403 | if (!isOwnSprite) {\r | |
404 | return sprite;\r | |
405 | }\r | |
406 | sprite.setParent(null);\r | |
407 | sprite.setSurface(null);\r | |
408 | Ext.Array.remove(me.getItems(), sprite);\r | |
409 | \r | |
410 | me.dirtyZIndex = true;\r | |
411 | me.setDirty(true);\r | |
412 | }\r | |
413 | \r | |
414 | return sprite || null;\r | |
415 | },\r | |
416 | \r | |
417 | /**\r | |
418 | * Remove all sprites from the surface, optionally destroying the sprites in the process.\r | |
419 | *\r | |
420 | * For example:\r | |
421 | *\r | |
422 | * drawContainer.getSurface('main').removeAll();\r | |
423 | *\r | |
424 | * @param {Boolean} [isDestroy=false]\r | |
425 | */\r | |
426 | removeAll: function (isDestroy) {\r | |
427 | var items = this.getItems(),\r | |
428 | i = items.length - 1,\r | |
429 | item;\r | |
430 | \r | |
431 | if (isDestroy) {\r | |
432 | for (; i >= 0; i--) {\r | |
433 | items[i].destroy();\r | |
434 | }\r | |
435 | } else {\r | |
436 | for (; i >= 0; i--) {\r | |
437 | item = items[i];\r | |
438 | item.setParent(null);\r | |
439 | item.setSurface(null);\r | |
440 | }\r | |
441 | }\r | |
442 | \r | |
443 | items.length = 0;\r | |
444 | this.map = {};\r | |
445 | this.dirtyZIndex = true;\r | |
446 | },\r | |
447 | \r | |
448 | /**\r | |
449 | * @private\r | |
450 | */\r | |
451 | applyItems: function (items) {\r | |
452 | if (this.getItems()) {\r | |
453 | this.removeAll(true);\r | |
454 | }\r | |
455 | return Ext.Array.from(this.add(items));\r | |
456 | },\r | |
457 | \r | |
458 | /**\r | |
459 | * @private\r | |
460 | * Creates an item and appends it to the surface. Called\r | |
461 | * as an internal method when calling `add`.\r | |
462 | */\r | |
463 | createItem: function (config) {\r | |
464 | return Ext.create(config.xclass || 'sprite.' + config.type, config);\r | |
465 | },\r | |
466 | \r | |
467 | /**\r | |
468 | * Return the minimal bounding box that contains all the sprites bounding boxes in the given list of sprites.\r | |
469 | * @param {Ext.draw.sprite.Sprite[]|Ext.draw.sprite.Sprite} sprites\r | |
470 | * @param {Boolean} [isWithoutTransform=false]\r | |
471 | * @return {{x: Number, y: Number, width: number, height: number}}\r | |
472 | */\r | |
473 | getBBox: function (sprites, isWithoutTransform) {\r | |
474 | var sprites = Ext.Array.from(sprites),\r | |
475 | left = Infinity,\r | |
476 | right = -Infinity,\r | |
477 | top = Infinity,\r | |
478 | bottom = -Infinity,\r | |
479 | sprite, bbox, i, ln;\r | |
480 | \r | |
481 | for (i = 0, ln = sprites.length; i < ln; i++) {\r | |
482 | sprite = sprites[i];\r | |
483 | bbox = sprite.getBBox(isWithoutTransform);\r | |
484 | if (left > bbox.x) {\r | |
485 | left = bbox.x;\r | |
486 | }\r | |
487 | if (right < bbox.x + bbox.width) {\r | |
488 | right = bbox.x + bbox.width;\r | |
489 | }\r | |
490 | if (top > bbox.y) {\r | |
491 | top = bbox.y;\r | |
492 | }\r | |
493 | if (bottom < bbox.y + bbox.height) {\r | |
494 | bottom = bbox.y + bbox.height;\r | |
495 | }\r | |
496 | }\r | |
497 | return {\r | |
498 | x: left,\r | |
499 | y: top,\r | |
500 | width: right - left,\r | |
501 | height: bottom - top\r | |
502 | };\r | |
503 | },\r | |
504 | \r | |
505 | emptyRect: [0, 0, 0, 0],\r | |
506 | \r | |
507 | // Converts event's page coordinates into surface coordinates.\r | |
508 | // Note: surface's x-coordinates always go LTR, regardless of RTL mode.\r | |
509 | getEventXY: function (e) {\r | |
510 | var me = this,\r | |
511 | isRtl = me.getInherited().rtl,\r | |
512 | pageXY = e.getXY(), // Event position in page coordinates.\r | |
513 | container = me.getOwnerBody(), // The body of the chart (doesn't include docked items like legend).\r | |
514 | xy = container.getXY(), // Surface container position in page coordinates.\r | |
515 | rect = me.getRect() || me.emptyRect, // Surface position in surface container coordinates (LTR).\r | |
516 | result = [],\r | |
517 | width;\r | |
518 | \r | |
519 | if (isRtl) {\r | |
520 | width = container.getWidth();\r | |
521 | // The line below is actually a simplified form of\r | |
522 | // rect[2] - (pageXY[0] - xy[0] - (width - (rect[0] + rect[2]))).\r | |
523 | result[0] = xy[0] - pageXY[0] - rect[0] + width;\r | |
524 | } else {\r | |
525 | result[0] = pageXY[0] - xy[0] - rect[0];\r | |
526 | }\r | |
527 | result[1] = pageXY[1] - xy[1] - rect[1];\r | |
528 | return result;\r | |
529 | },\r | |
530 | \r | |
531 | /**\r | |
532 | * Empty the surface content (without touching the sprites.)\r | |
533 | */\r | |
534 | clear: Ext.emptyFn,\r | |
535 | \r | |
536 | /**\r | |
537 | * @private\r | |
538 | * Order the items by their z-index if any of that has been changed since last sort.\r | |
539 | */\r | |
540 | orderByZIndex: function () {\r | |
541 | var me = this,\r | |
542 | items = me.getItems(),\r | |
543 | dirtyZIndex = false,\r | |
544 | i, ln;\r | |
545 | \r | |
546 | if (me.getDirty()) {\r | |
547 | for (i = 0, ln = items.length; i < ln; i++) {\r | |
548 | if (items[i].attr.dirtyZIndex) {\r | |
549 | dirtyZIndex = true;\r | |
550 | break;\r | |
551 | }\r | |
552 | }\r | |
553 | if (dirtyZIndex) {\r | |
554 | // sort by zIndex\r | |
555 | Ext.Array.sort(items, function (a, b) {\r | |
556 | return a.attr.zIndex - b.attr.zIndex;\r | |
557 | });\r | |
558 | this.setDirty(true);\r | |
559 | }\r | |
560 | \r | |
561 | for (i = 0, ln = items.length; i < ln; i++) {\r | |
562 | items[i].attr.dirtyZIndex = false;\r | |
563 | }\r | |
564 | }\r | |
565 | },\r | |
566 | \r | |
567 | /**\r | |
568 | * Force the element to redraw.\r | |
569 | */\r | |
570 | repaint: function () {\r | |
571 | var me = this;\r | |
572 | me.repaint = Ext.emptyFn;\r | |
573 | Ext.defer(function () {\r | |
574 | delete me.repaint;\r | |
575 | me.element.repaint();\r | |
576 | }, 1);\r | |
577 | },\r | |
578 | \r | |
579 | /**\r | |
580 | * Triggers the re-rendering of the canvas.\r | |
581 | */\r | |
582 | renderFrame: function () {\r | |
583 | var me = this;\r | |
584 | \r | |
585 | if (!me.element) {\r | |
586 | return;\r | |
587 | }\r | |
588 | if (me.dirtyPredecessorCount > 0) {\r | |
589 | me.isPendingRenderFrame = true;\r | |
590 | return;\r | |
591 | }\r | |
592 | \r | |
593 | var rect = me.getRect(),\r | |
594 | background = me.getBackground(),\r | |
595 | items = me.getItems(),\r | |
596 | item, i, ln;\r | |
597 | \r | |
598 | // Cannot render before the surface is placed.\r | |
599 | if (!rect) {\r | |
600 | return;\r | |
601 | }\r | |
602 | \r | |
603 | // This will also check the dirty flags of the sprites.\r | |
604 | me.orderByZIndex();\r | |
605 | if (me.getDirty()) {\r | |
606 | me.clear();\r | |
607 | me.clearTransform();\r | |
608 | \r | |
609 | if (background) {\r | |
610 | me.renderSprite(background);\r | |
611 | }\r | |
612 | \r | |
613 | for (i = 0, ln = items.length; i < ln; i++) {\r | |
614 | item = items[i];\r | |
615 | if (me.renderSprite(item) === false) {\r | |
616 | return;\r | |
617 | }\r | |
618 | item.attr.textPositionCount = me.textPosition;\r | |
619 | }\r | |
620 | \r | |
621 | me.setDirty(false);\r | |
622 | }\r | |
623 | },\r | |
624 | \r | |
625 | /**\r | |
626 | * @method\r | |
627 | * @private\r | |
628 | * Renders a single sprite into the surface.\r | |
629 | * Do not call it from outside `renderFrame` method.\r | |
630 | *\r | |
631 | * @param {Ext.draw.sprite.Sprite} sprite The Sprite to be rendered.\r | |
632 | * @return {Boolean} returns `false` to stop the rendering to continue.\r | |
633 | */\r | |
634 | renderSprite: Ext.emptyFn,\r | |
635 | \r | |
636 | /**\r | |
637 | * @method flatten\r | |
638 | * Flattens the given drawing surfaces into a single image\r | |
639 | * and returns an object containing the data (in the DataURL format)\r | |
640 | * and the type (e.g. 'png' or 'svg') of that image.\r | |
641 | * @param {Object} size The size of the final image.\r | |
642 | * @param {Number} size.width\r | |
643 | * @param {Number} size.height\r | |
644 | * @param {Ext.draw.Surface[]} surfaces The surfaces to flatten.\r | |
645 | * @return {Object}\r | |
646 | * @return {String} return.data The DataURL of the flattened image.\r | |
647 | * @return {String} return.type The type of the image.\r | |
648 | *\r | |
649 | */\r | |
650 | \r | |
651 | /**\r | |
652 | * @private\r | |
653 | * Clears the current transformation state on the surface.\r | |
654 | */\r | |
655 | clearTransform: Ext.emptyFn,\r | |
656 | \r | |
657 | /**\r | |
658 | * Destroys the surface. This is done by removing all components from it and\r | |
659 | * also removing its reference to a DOM element.\r | |
660 | *\r | |
661 | * For example:\r | |
662 | *\r | |
663 | * drawContainer.surface.destroy();\r | |
664 | */\r | |
665 | destroy: function () {\r | |
666 | var me = this;\r | |
667 | \r | |
668 | me.removeAll(true);\r | |
669 | me.predecessors = null;\r | |
670 | me.successors = null;\r | |
671 | \r | |
672 | me.callParent();\r | |
673 | }\r | |
674 | });\r | |
675 | \r | |
676 | \r |