Surface.html 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-draw-Surface'>/**
  19. </span> * A Surface is an interface to render methods inside {@link Ext.draw.Component}.
  20. *
  21. * Most of the Surface methods are abstract and they have a concrete implementation
  22. * in {@link Ext.draw.engine.Vml VML} or {@link Ext.draw.engine.Svg SVG} engines.
  23. *
  24. * A Surface contains methods to render {@link Ext.draw.Sprite sprites}, get bounding
  25. * boxes of sprites, add sprites to the canvas, initialize other graphic components, etc.
  26. *
  27. * ## Adding sprites to surface
  28. *
  29. * One of the most used methods for this class is the {@link #add} method, to add Sprites to
  30. * the surface. For example:
  31. *
  32. * drawComponent.surface.add({
  33. * type: 'circle',
  34. * fill: '#ffc',
  35. * radius: 100,
  36. * x: 100,
  37. * y: 100
  38. * });
  39. *
  40. * The configuration object passed in the `add` method is the same as described in the
  41. * {@link Ext.draw.Sprite} class documentation.
  42. *
  43. * Sprites can also be added to surface by setting their surface config at creation time:
  44. *
  45. * var sprite = Ext.create('Ext.draw.Sprite', {
  46. * type: 'circle',
  47. * fill: '#ff0',
  48. * surface: drawComponent.surface,
  49. * radius: 5
  50. * });
  51. *
  52. * In order to properly apply properties and render the sprite we have to
  53. * `show` the sprite setting the option `redraw` to `true`:
  54. *
  55. * sprite.show(true);
  56. *
  57. */
  58. Ext.define('Ext.draw.Surface', {
  59. /* Begin Definitions */
  60. mixins: {
  61. observable: 'Ext.util.Observable'
  62. },
  63. requires: ['Ext.draw.CompositeSprite'],
  64. uses: ['Ext.draw.engine.Svg', 'Ext.draw.engine.Vml', 'Ext.draw.engine.SvgExporter', 'Ext.draw.engine.ImageExporter'],
  65. separatorRe: /[, ]+/,
  66. statics: {
  67. <span id='Ext-draw-Surface-static-method-create'> /**
  68. </span> * Creates and returns a new concrete Surface instance appropriate for the current environment.
  69. * @param {Object} config Initial configuration for the Surface instance
  70. * @param {String[]} enginePriority (Optional) order of implementations to use; the first one that is
  71. * available in the current environment will be used. Defaults to `['Svg', 'Vml']`.
  72. * @return {Object} The created Surface or false.
  73. * @static
  74. */
  75. create: function(config, enginePriority) {
  76. enginePriority = enginePriority || ['Svg', 'Vml'];
  77. var i = 0,
  78. len = enginePriority.length,
  79. surfaceClass;
  80. for (; i &lt; len; i++) {
  81. if (Ext.supports[enginePriority[i]] !== false) {
  82. return Ext.create('Ext.draw.engine.' + enginePriority[i], config);
  83. }
  84. }
  85. return false;
  86. },
  87. <span id='Ext-draw-Surface-static-method-save'> /**
  88. </span> * Exports a {@link Ext.draw.Surface surface} in a different format.
  89. * The surface may be exported to an SVG string, using the
  90. * {@link Ext.draw.engine.SvgExporter}. It may also be exported
  91. * as an image using the {@link Ext.draw.engine.ImageExporter ImageExporter}.
  92. * Note that this requires sending data to a remote server to process
  93. * the SVG into an image, see the {@link Ext.draw.engine.ImageExporter} for
  94. * more details.
  95. * @param {Ext.draw.Surface} surface The surface to export.
  96. * @param {Object} [config] The configuration to be passed to the exporter.
  97. * See the export method for the appropriate exporter for the relevant
  98. * configuration options
  99. * @return {Object} See the return types for the appropriate exporter
  100. * @static
  101. */
  102. save: function(surface, config) {
  103. config = config || {};
  104. var exportTypes = {
  105. 'image/png': 'Image',
  106. 'image/jpeg': 'Image',
  107. 'image/svg+xml': 'Svg'
  108. },
  109. prefix = exportTypes[config.type] || 'Svg',
  110. exporter = Ext.draw.engine[prefix + 'Exporter'];
  111. return exporter.generate(surface, config);
  112. }
  113. },
  114. /* End Definitions */
  115. // @private
  116. availableAttrs: {
  117. blur: 0,
  118. &quot;clip-rect&quot;: &quot;0 0 1e9 1e9&quot;,
  119. cursor: &quot;default&quot;,
  120. cx: 0,
  121. cy: 0,
  122. 'dominant-baseline': 'auto',
  123. fill: &quot;none&quot;,
  124. &quot;fill-opacity&quot;: 1,
  125. font: '10px &quot;Arial&quot;',
  126. &quot;font-family&quot;: '&quot;Arial&quot;',
  127. &quot;font-size&quot;: &quot;10&quot;,
  128. &quot;font-style&quot;: &quot;normal&quot;,
  129. &quot;font-weight&quot;: 400,
  130. gradient: &quot;&quot;,
  131. height: 0,
  132. hidden: false,
  133. href: &quot;http://sencha.com/&quot;,
  134. opacity: 1,
  135. path: &quot;M0,0&quot;,
  136. radius: 0,
  137. rx: 0,
  138. ry: 0,
  139. scale: &quot;1 1&quot;,
  140. src: &quot;&quot;,
  141. stroke: &quot;none&quot;,
  142. &quot;stroke-dasharray&quot;: &quot;&quot;,
  143. &quot;stroke-linecap&quot;: &quot;butt&quot;,
  144. &quot;stroke-linejoin&quot;: &quot;butt&quot;,
  145. &quot;stroke-miterlimit&quot;: 0,
  146. &quot;stroke-opacity&quot;: 1,
  147. &quot;stroke-width&quot;: 1,
  148. target: &quot;_blank&quot;,
  149. text: &quot;&quot;,
  150. &quot;text-anchor&quot;: &quot;middle&quot;,
  151. title: &quot;Ext Draw&quot;,
  152. width: 0,
  153. x: 0,
  154. y: 0,
  155. zIndex: 0
  156. },
  157. <span id='Ext-draw-Surface-cfg-height'> /**
  158. </span> * @cfg {Number} height
  159. * The height of this component in pixels (defaults to auto).
  160. */
  161. <span id='Ext-draw-Surface-cfg-width'> /**
  162. </span> * @cfg {Number} width
  163. * The width of this component in pixels (defaults to auto).
  164. */
  165. container: undefined,
  166. height: 352,
  167. width: 512,
  168. x: 0,
  169. y: 0,
  170. <span id='Ext-draw-Surface-cfg-items'> /**
  171. </span> * @cfg {Ext.draw.Sprite[]} items
  172. * Array of sprites or sprite config objects to add initially to the surface.
  173. */
  174. <span id='Ext-draw-Surface-property-orderSpritesByZIndex'> /**
  175. </span> * @private Flag indicating that the surface implementation requires sprites to be maintained
  176. * in order of their zIndex. Impls that don't require this can set it to false.
  177. */
  178. orderSpritesByZIndex: true,
  179. <span id='Ext-draw-Surface-method-constructor'> /**
  180. </span> * Creates new Surface.
  181. * @param {Object} config (optional) Config object.
  182. */
  183. constructor: function(config) {
  184. var me = this;
  185. config = config || {};
  186. Ext.apply(me, config);
  187. me.domRef = Ext.getDoc().dom;
  188. me.customAttributes = {};
  189. me.addEvents(
  190. <span id='Ext-draw-Surface-event-mousedown'> /**
  191. </span> * @event
  192. * Fires when a mousedown is detected within the surface.
  193. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  194. */
  195. 'mousedown',
  196. <span id='Ext-draw-Surface-event-mouseup'> /**
  197. </span> * @event
  198. * Fires when a mouseup is detected within the surface.
  199. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  200. */
  201. 'mouseup',
  202. <span id='Ext-draw-Surface-event-mouseover'> /**
  203. </span> * @event
  204. * Fires when a mouseover is detected within the surface.
  205. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  206. */
  207. 'mouseover',
  208. <span id='Ext-draw-Surface-event-mouseout'> /**
  209. </span> * @event
  210. * Fires when a mouseout is detected within the surface.
  211. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  212. */
  213. 'mouseout',
  214. <span id='Ext-draw-Surface-event-mousemove'> /**
  215. </span> * @event
  216. * Fires when a mousemove is detected within the surface.
  217. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  218. */
  219. 'mousemove',
  220. <span id='Ext-draw-Surface-event-mouseenter'> /**
  221. </span> * @event
  222. * Fires when a mouseenter is detected within the surface.
  223. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  224. */
  225. 'mouseenter',
  226. <span id='Ext-draw-Surface-event-mouseleave'> /**
  227. </span> * @event
  228. * Fires when a mouseleave is detected within the surface.
  229. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  230. */
  231. 'mouseleave',
  232. <span id='Ext-draw-Surface-event-click'> /**
  233. </span> * @event
  234. * Fires when a click is detected within the surface.
  235. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  236. */
  237. 'click',
  238. <span id='Ext-draw-Surface-event-dblclick'> /**
  239. </span> * @event
  240. * Fires when a dblclick is detected within the surface.
  241. * @param {Ext.EventObject} e An object encapsulating the DOM event.
  242. */
  243. 'dblclick'
  244. );
  245. me.mixins.observable.constructor.call(me);
  246. me.getId();
  247. me.initGradients();
  248. me.initItems();
  249. if (me.renderTo) {
  250. me.render(me.renderTo);
  251. delete me.renderTo;
  252. }
  253. me.initBackground(config.background);
  254. },
  255. // @private called to initialize components in the surface
  256. // this is dependent on the underlying implementation.
  257. initSurface: Ext.emptyFn,
  258. // @private called to setup the surface to render an item
  259. //this is dependent on the underlying implementation.
  260. renderItem: Ext.emptyFn,
  261. // @private
  262. renderItems: Ext.emptyFn,
  263. // @private
  264. setViewBox: function (x, y, width, height) {
  265. if (isFinite(x) &amp;&amp; isFinite(y) &amp;&amp; isFinite(width) &amp;&amp; isFinite(height)) {
  266. this.viewBox = {x: x, y: y, width: width, height: height};
  267. this.applyViewBox();
  268. }
  269. },
  270. <span id='Ext-draw-Surface-method-addCls'> /**
  271. </span> * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
  272. *
  273. * For example:
  274. *
  275. * drawComponent.surface.addCls(sprite, 'x-visible');
  276. *
  277. * @param {Object} sprite The sprite to add the class to.
  278. * @param {String/String[]} className The CSS class to add, or an array of classes
  279. * @method
  280. */
  281. addCls: Ext.emptyFn,
  282. <span id='Ext-draw-Surface-method-removeCls'> /**
  283. </span> * Removes one or more CSS classes from the element.
  284. *
  285. * For example:
  286. *
  287. * drawComponent.surface.removeCls(sprite, 'x-visible');
  288. *
  289. * @param {Object} sprite The sprite to remove the class from.
  290. * @param {String/String[]} className The CSS class to remove, or an array of classes
  291. * @method
  292. */
  293. removeCls: Ext.emptyFn,
  294. <span id='Ext-draw-Surface-method-setStyle'> /**
  295. </span> * Sets CSS style attributes to an element.
  296. *
  297. * For example:
  298. *
  299. * drawComponent.surface.setStyle(sprite, {
  300. * 'cursor': 'pointer'
  301. * });
  302. *
  303. * @param {Object} sprite The sprite to add, or an array of classes to
  304. * @param {Object} styles An Object with CSS styles.
  305. * @method
  306. */
  307. setStyle: Ext.emptyFn,
  308. // @private
  309. initGradients: function() {
  310. if (this.hasOwnProperty('gradients')) {
  311. var gradients = this.gradients,
  312. gLen = gradients.length,
  313. fn = this.addGradient,
  314. g;
  315. if (gradients) {
  316. for (g = 0; g &lt; gLen; g++) {
  317. if (fn.call(this, gradients[g], g, gLen) === false) {
  318. break;
  319. }
  320. }
  321. }
  322. }
  323. },
  324. // @private
  325. initItems: function() {
  326. var items = this.items;
  327. this.items = new Ext.draw.CompositeSprite();
  328. this.items.autoDestroy = true;
  329. this.groups = new Ext.draw.CompositeSprite();
  330. if (items) {
  331. this.add(items);
  332. }
  333. },
  334. // @private
  335. initBackground: function(config) {
  336. var me = this,
  337. width = me.width,
  338. height = me.height,
  339. gradientId, gradient, backgroundSprite;
  340. if (Ext.isString(config)) {
  341. config = {
  342. fill : config
  343. };
  344. }
  345. if (config) {
  346. if (config.gradient) {
  347. gradient = config.gradient;
  348. gradientId = gradient.id;
  349. me.addGradient(gradient);
  350. me.background = me.add({
  351. type: 'rect',
  352. x: 0,
  353. y: 0,
  354. width: width,
  355. height: height,
  356. fill: 'url(#' + gradientId + ')',
  357. zIndex: -1
  358. });
  359. } else if (config.fill) {
  360. me.background = me.add({
  361. type: 'rect',
  362. x: 0,
  363. y: 0,
  364. width: width,
  365. height: height,
  366. fill: config.fill,
  367. zIndex: -1
  368. });
  369. } else if (config.image) {
  370. me.background = me.add({
  371. type: 'image',
  372. x: 0,
  373. y: 0,
  374. width: width,
  375. height: height,
  376. src: config.image,
  377. zIndex: -1
  378. });
  379. }
  380. // prevent me.background to jeopardize me.items.getBBox
  381. me.background.bboxExcluded = true;
  382. }
  383. },
  384. <span id='Ext-draw-Surface-method-setSize'> /**
  385. </span> * Sets the size of the surface. Accomodates the background (if any) to fit the new size too.
  386. *
  387. * For example:
  388. *
  389. * drawComponent.surface.setSize(500, 500);
  390. *
  391. * This method is generally called when also setting the size of the draw Component.
  392. *
  393. * @param {Number} w The new width of the canvas.
  394. * @param {Number} h The new height of the canvas.
  395. */
  396. setSize: function(w, h) {
  397. this.applyViewBox();
  398. },
  399. // @private
  400. scrubAttrs: function(sprite) {
  401. var i,
  402. attrs = {},
  403. exclude = {},
  404. sattr = sprite.attr;
  405. for (i in sattr) {
  406. // Narrow down attributes to the main set
  407. if (this.translateAttrs.hasOwnProperty(i)) {
  408. // Translated attr
  409. attrs[this.translateAttrs[i]] = sattr[i];
  410. exclude[this.translateAttrs[i]] = true;
  411. }
  412. else if (this.availableAttrs.hasOwnProperty(i) &amp;&amp; !exclude[i]) {
  413. // Passtrhough attr
  414. attrs[i] = sattr[i];
  415. }
  416. }
  417. return attrs;
  418. },
  419. // @private
  420. onClick: function(e) {
  421. this.processEvent('click', e);
  422. },
  423. // @private
  424. onDblClick: function(e) {
  425. this.processEvent('dblclick', e);
  426. },
  427. // @private
  428. onMouseUp: function(e) {
  429. this.processEvent('mouseup', e);
  430. },
  431. // @private
  432. onMouseDown: function(e) {
  433. this.processEvent('mousedown', e);
  434. },
  435. // @private
  436. onMouseOver: function(e) {
  437. this.processEvent('mouseover', e);
  438. },
  439. // @private
  440. onMouseOut: function(e) {
  441. this.processEvent('mouseout', e);
  442. },
  443. // @private
  444. onMouseMove: function(e) {
  445. this.fireEvent('mousemove', e);
  446. },
  447. // @private
  448. onMouseEnter: Ext.emptyFn,
  449. // @private
  450. onMouseLeave: Ext.emptyFn,
  451. <span id='Ext-draw-Surface-method-addGradient'> /**
  452. </span> * Adds a gradient definition to the Surface. Note that in some surface engines, adding
  453. * a gradient via this method will not take effect if the surface has already been rendered.
  454. * Therefore, it is preferred to pass the gradients as an item to the surface config, rather
  455. * than calling this method, especially if the surface is rendered immediately (e.g. due to
  456. * 'renderTo' in its config). For more information on how to create gradients in the Chart
  457. * configuration object please refer to {@link Ext.chart.Chart}.
  458. *
  459. * The gradient object to be passed into this method is composed by:
  460. *
  461. * - **id** - string - The unique name of the gradient.
  462. * - **angle** - number, optional - The angle of the gradient in degrees.
  463. * - **stops** - object - An object with numbers as keys (from 0 to 100) and style objects as values.
  464. *
  465. * For example:
  466. *
  467. * drawComponent.surface.addGradient({
  468. * id: 'gradientId',
  469. * angle: 45,
  470. * stops: {
  471. * 0: {
  472. * color: '#555'
  473. * },
  474. * 100: {
  475. * color: '#ddd'
  476. * }
  477. * }
  478. * });
  479. *
  480. * @param {Object} gradient A gradient config.
  481. * @method
  482. */
  483. addGradient: Ext.emptyFn,
  484. <span id='Ext-draw-Surface-method-add'> /**
  485. </span> * Adds a Sprite to the surface. See {@link Ext.draw.Sprite} for the configuration object to be
  486. * passed into this method.
  487. *
  488. * For example:
  489. *
  490. * drawComponent.surface.add({
  491. * type: 'circle',
  492. * fill: '#ffc',
  493. * radius: 100,
  494. * x: 100,
  495. * y: 100
  496. * });
  497. *
  498. * @param {Ext.draw.Sprite[]/Ext.draw.Sprite...} args One or more Sprite objects or configs.
  499. * @return {Ext.draw.Sprite[]/Ext.draw.Sprite} The sprites added.
  500. */
  501. add: function() {
  502. var args = Array.prototype.slice.call(arguments),
  503. sprite,
  504. index,
  505. hasMultipleArgs = args.length &gt; 1,
  506. items,
  507. results,
  508. i,
  509. ln,
  510. item;
  511. if (hasMultipleArgs || Ext.isArray(args[0])) {
  512. items = hasMultipleArgs ? args : args[0];
  513. results = [];
  514. for (i = 0, ln = items.length; i &lt; ln; i++) {
  515. item = items[i];
  516. item = this.add(item);
  517. results.push(item);
  518. }
  519. return results;
  520. }
  521. sprite = this.prepareItems(args[0], true)[0];
  522. this.insertByZIndex(sprite);
  523. this.onAdd(sprite);
  524. return sprite;
  525. },
  526. <span id='Ext-draw-Surface-method-insertByZIndex'> /**
  527. </span> * @private
  528. * Inserts a given sprite into the correct position in the items collection, according to
  529. * its zIndex. It will be inserted at the end of an existing series of sprites with the same or
  530. * lower zIndex. By ensuring sprites are always ordered, this allows surface subclasses to render
  531. * the sprites in the correct order for proper z-index stacking.
  532. * @param {Ext.draw.Sprite} sprite
  533. * @return {Number} the sprite's new index in the list
  534. */
  535. insertByZIndex: function(sprite) {
  536. var me = this,
  537. sprites = me.items.items,
  538. len = sprites.length,
  539. ceil = Math.ceil,
  540. zIndex = sprite.attr.zIndex,
  541. idx = len,
  542. high = idx - 1,
  543. low = 0,
  544. otherZIndex;
  545. if (me.orderSpritesByZIndex &amp;&amp; len &amp;&amp; zIndex &lt; sprites[high].attr.zIndex) {
  546. // Find the target index via a binary search for speed
  547. while (low &lt;= high) {
  548. idx = ceil((low + high) / 2);
  549. otherZIndex = sprites[idx].attr.zIndex;
  550. if (otherZIndex &gt; zIndex) {
  551. high = idx - 1;
  552. }
  553. else if (otherZIndex &lt; zIndex) {
  554. low = idx + 1;
  555. }
  556. else {
  557. break;
  558. }
  559. }
  560. // Step forward to the end of a sequence of the same or lower z-index
  561. while (idx &lt; len &amp;&amp; sprites[idx].attr.zIndex &lt;= zIndex) {
  562. idx++;
  563. }
  564. }
  565. me.items.insert(idx, sprite);
  566. return idx;
  567. },
  568. onAdd: function(sprite) {
  569. var group = sprite.group,
  570. draggable = sprite.draggable,
  571. groups, ln, i;
  572. if (group) {
  573. groups = [].concat(group);
  574. ln = groups.length;
  575. for (i = 0; i &lt; ln; i++) {
  576. group = groups[i];
  577. this.getGroup(group).add(sprite);
  578. }
  579. delete sprite.group;
  580. }
  581. if (draggable) {
  582. sprite.initDraggable();
  583. }
  584. },
  585. <span id='Ext-draw-Surface-method-remove'> /**
  586. </span> * Removes a given sprite from the surface, optionally destroying the sprite in the process.
  587. * You can also call the sprite own `remove` method.
  588. *
  589. * For example:
  590. *
  591. * drawComponent.surface.remove(sprite);
  592. * //or...
  593. * sprite.remove();
  594. *
  595. * @param {Ext.draw.Sprite} sprite
  596. * @param {Boolean} destroySprite
  597. */
  598. remove: function(sprite, destroySprite) {
  599. if (sprite) {
  600. this.items.remove(sprite);
  601. var groups = [].concat(this.groups.items),
  602. gLen = groups.length,
  603. g;
  604. for (g = 0; g &lt; gLen; g++) {
  605. groups[g].remove(sprite);
  606. }
  607. sprite.onRemove();
  608. if (destroySprite === true) {
  609. sprite.destroy();
  610. }
  611. }
  612. },
  613. <span id='Ext-draw-Surface-method-removeAll'> /**
  614. </span> * Removes all sprites from the surface, optionally destroying the sprites in the process.
  615. *
  616. * For example:
  617. *
  618. * drawComponent.surface.removeAll();
  619. *
  620. * @param {Boolean} destroySprites Whether to destroy all sprites when removing them.
  621. */
  622. removeAll: function(destroySprites) {
  623. var items = this.items.items,
  624. ln = items.length,
  625. i;
  626. for (i = ln - 1; i &gt; -1; i--) {
  627. this.remove(items[i], destroySprites);
  628. }
  629. },
  630. onRemove: Ext.emptyFn,
  631. onDestroy: Ext.emptyFn,
  632. <span id='Ext-draw-Surface-method-applyViewBox'> /**
  633. </span> * @private Using the current viewBox property and the surface's width and height, calculate the
  634. * appropriate viewBoxShift that will be applied as a persistent transform to all sprites.
  635. */
  636. applyViewBox: function() {
  637. var me = this,
  638. viewBox = me.viewBox,
  639. width = me.width || 1, // Avoid problems in division
  640. height = me.height || 1,
  641. viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight,
  642. relativeHeight, relativeWidth, size;
  643. if (viewBox &amp;&amp; (width || height)) {
  644. viewBoxX = viewBox.x;
  645. viewBoxY = viewBox.y;
  646. viewBoxWidth = viewBox.width;
  647. viewBoxHeight = viewBox.height;
  648. relativeHeight = height / viewBoxHeight;
  649. relativeWidth = width / viewBoxWidth;
  650. size = Math.min(relativeWidth, relativeHeight);
  651. if (viewBoxWidth * size &lt; width) {
  652. viewBoxX -= (width - viewBoxWidth * size) / 2 / size;
  653. }
  654. if (viewBoxHeight * size &lt; height) {
  655. viewBoxY -= (height - viewBoxHeight * size) / 2 / size;
  656. }
  657. me.viewBoxShift = {
  658. dx: -viewBoxX,
  659. dy: -viewBoxY,
  660. scale: size
  661. };
  662. if (me.background) {
  663. me.background.setAttributes(Ext.apply({}, {
  664. x: viewBoxX,
  665. y: viewBoxY,
  666. width: width / size,
  667. height: height / size
  668. }, { hidden: false }), true);
  669. }
  670. } else {
  671. if (me.background &amp;&amp; width &amp;&amp; height) {
  672. me.background.setAttributes(Ext.apply({x: 0, y: 0, width: width, height: height}, { hidden: false }), true);
  673. }
  674. }
  675. },
  676. getBBox: function (sprite, isWithoutTransform) {
  677. var realPath = this[&quot;getPath&quot; + sprite.type](sprite);
  678. if (isWithoutTransform) {
  679. sprite.bbox.plain = sprite.bbox.plain || Ext.draw.Draw.pathDimensions(realPath);
  680. return sprite.bbox.plain;
  681. }
  682. if (sprite.dirtyTransform) {
  683. this.applyTransformations(sprite, true);
  684. }
  685. sprite.bbox.transform = sprite.bbox.transform || Ext.draw.Draw.pathDimensions(Ext.draw.Draw.mapPath(realPath, sprite.matrix));
  686. return sprite.bbox.transform;
  687. },
  688. transformToViewBox: function (x, y) {
  689. if (this.viewBoxShift) {
  690. var me = this, shift = me.viewBoxShift;
  691. return [x / shift.scale - shift.dx, y / shift.scale - shift.dy];
  692. } else {
  693. return [x, y];
  694. }
  695. },
  696. // @private
  697. applyTransformations: function(sprite, onlyMatrix) {
  698. if (sprite.type == 'text') {
  699. // TODO: getTextBBox function always take matrix into account no matter whether `isWithoutTransform` is true. Fix that.
  700. sprite.bbox.transform = 0;
  701. this.transform(sprite, false);
  702. }
  703. sprite.dirtyTransform = false;
  704. var me = this,
  705. attr = sprite.attr;
  706. if (attr.translation.x != null || attr.translation.y != null) {
  707. me.translate(sprite);
  708. }
  709. if (attr.scaling.x != null || attr.scaling.y != null) {
  710. me.scale(sprite);
  711. }
  712. if (attr.rotation.degrees != null) {
  713. me.rotate(sprite);
  714. }
  715. sprite.bbox.transform = 0;
  716. this.transform(sprite, onlyMatrix);
  717. sprite.transformations = [];
  718. },
  719. // @private
  720. rotate: function (sprite) {
  721. var bbox,
  722. deg = sprite.attr.rotation.degrees,
  723. centerX = sprite.attr.rotation.x,
  724. centerY = sprite.attr.rotation.y;
  725. if (!Ext.isNumber(centerX) || !Ext.isNumber(centerY)) {
  726. bbox = this.getBBox(sprite, true);
  727. centerX = !Ext.isNumber(centerX) ? bbox.x + bbox.width / 2 : centerX;
  728. centerY = !Ext.isNumber(centerY) ? bbox.y + bbox.height / 2 : centerY;
  729. }
  730. sprite.transformations.push({
  731. type: &quot;rotate&quot;,
  732. degrees: deg,
  733. x: centerX,
  734. y: centerY
  735. });
  736. },
  737. // @private
  738. translate: function(sprite) {
  739. var x = sprite.attr.translation.x || 0,
  740. y = sprite.attr.translation.y || 0;
  741. sprite.transformations.push({
  742. type: &quot;translate&quot;,
  743. x: x,
  744. y: y
  745. });
  746. },
  747. // @private
  748. scale: function(sprite) {
  749. var bbox,
  750. x = sprite.attr.scaling.x || 1,
  751. y = sprite.attr.scaling.y || 1,
  752. centerX = sprite.attr.scaling.centerX,
  753. centerY = sprite.attr.scaling.centerY;
  754. if (!Ext.isNumber(centerX) || !Ext.isNumber(centerY)) {
  755. bbox = this.getBBox(sprite, true);
  756. centerX = !Ext.isNumber(centerX) ? bbox.x + bbox.width / 2 : centerX;
  757. centerY = !Ext.isNumber(centerY) ? bbox.y + bbox.height / 2 : centerY;
  758. }
  759. sprite.transformations.push({
  760. type: &quot;scale&quot;,
  761. x: x,
  762. y: y,
  763. centerX: centerX,
  764. centerY: centerY
  765. });
  766. },
  767. // @private
  768. rectPath: function (x, y, w, h, r) {
  769. if (r) {
  770. return [[&quot;M&quot;, x + r, y], [&quot;l&quot;, w - r * 2, 0], [&quot;a&quot;, r, r, 0, 0, 1, r, r], [&quot;l&quot;, 0, h - r * 2], [&quot;a&quot;, r, r, 0, 0, 1, -r, r], [&quot;l&quot;, r * 2 - w, 0], [&quot;a&quot;, r, r, 0, 0, 1, -r, -r], [&quot;l&quot;, 0, r * 2 - h], [&quot;a&quot;, r, r, 0, 0, 1, r, -r], [&quot;z&quot;]];
  771. }
  772. return [[&quot;M&quot;, x, y], [&quot;l&quot;, w, 0], [&quot;l&quot;, 0, h], [&quot;l&quot;, -w, 0], [&quot;z&quot;]];
  773. },
  774. // @private
  775. ellipsePath: function (x, y, rx, ry) {
  776. if (ry == null) {
  777. ry = rx;
  778. }
  779. return [[&quot;M&quot;, x, y], [&quot;m&quot;, 0, -ry], [&quot;a&quot;, rx, ry, 0, 1, 1, 0, 2 * ry], [&quot;a&quot;, rx, ry, 0, 1, 1, 0, -2 * ry], [&quot;z&quot;]];
  780. },
  781. // @private
  782. getPathpath: function (el) {
  783. return el.attr.path;
  784. },
  785. // @private
  786. getPathcircle: function (el) {
  787. var a = el.attr;
  788. return this.ellipsePath(a.x, a.y, a.radius, a.radius);
  789. },
  790. // @private
  791. getPathellipse: function (el) {
  792. var a = el.attr;
  793. return this.ellipsePath(a.x, a.y,
  794. a.radiusX || (a.width / 2) || 0,
  795. a.radiusY || (a.height / 2) || 0);
  796. },
  797. // @private
  798. getPathrect: function (el) {
  799. var a = el.attr;
  800. return this.rectPath(a.x || 0, a.y || 0, a.width || 0, a.height || 0, a.r || 0);
  801. },
  802. // @private
  803. getPathimage: function (el) {
  804. var a = el.attr;
  805. return this.rectPath(a.x || 0, a.y || 0, a.width, a.height);
  806. },
  807. // @private
  808. getPathtext: function (el) {
  809. var bbox = this.getBBoxText(el);
  810. return this.rectPath(bbox.x, bbox.y, bbox.width, bbox.height);
  811. },
  812. createGroup: function(id) {
  813. var group = this.groups.get(id);
  814. if (!group) {
  815. group = new Ext.draw.CompositeSprite({
  816. surface: this
  817. });
  818. group.id = id || Ext.id(null, 'ext-surface-group-');
  819. this.groups.add(group);
  820. }
  821. return group;
  822. },
  823. <span id='Ext-draw-Surface-method-getGroup'> /**
  824. </span> * Returns a new group or an existent group associated with the current surface.
  825. * The group returned is a {@link Ext.draw.CompositeSprite} group.
  826. *
  827. * For example:
  828. *
  829. * var spriteGroup = drawComponent.surface.getGroup('someGroupId');
  830. *
  831. * @param {String} id The unique identifier of the group.
  832. * @return {Object} The {@link Ext.draw.CompositeSprite}.
  833. */
  834. getGroup: function(id) {
  835. var group;
  836. if (typeof id == &quot;string&quot;) {
  837. group = this.groups.get(id);
  838. if (!group) {
  839. group = this.createGroup(id);
  840. }
  841. } else {
  842. group = id;
  843. }
  844. return group;
  845. },
  846. // @private
  847. prepareItems: function(items, applyDefaults) {
  848. items = [].concat(items);
  849. // Make sure defaults are applied and item is initialized
  850. var item, i, ln;
  851. for (i = 0, ln = items.length; i &lt; ln; i++) {
  852. item = items[i];
  853. if (!(item instanceof Ext.draw.Sprite)) {
  854. // Temporary, just take in configs...
  855. item.surface = this;
  856. items[i] = this.createItem(item);
  857. } else {
  858. item.surface = this;
  859. }
  860. }
  861. return items;
  862. },
  863. <span id='Ext-draw-Surface-method-setText'> /**
  864. </span> * Changes the text in the sprite element. The sprite must be a `text` sprite.
  865. * This method can also be called from {@link Ext.draw.Sprite}.
  866. *
  867. * For example:
  868. *
  869. * var spriteGroup = drawComponent.surface.setText(sprite, 'my new text');
  870. *
  871. * @param {Object} sprite The Sprite to change the text.
  872. * @param {String} text The new text to be set.
  873. * @method
  874. */
  875. setText: Ext.emptyFn,
  876. // @private Creates an item and appends it to the surface. Called
  877. // as an internal method when calling `add`.
  878. createItem: Ext.emptyFn,
  879. <span id='Ext-draw-Surface-method-getId'> /**
  880. </span> * Retrieves the id of this component.
  881. * Will autogenerate an id if one has not already been set.
  882. */
  883. getId: function() {
  884. return this.id || (this.id = Ext.id(null, 'ext-surface-'));
  885. },
  886. <span id='Ext-draw-Surface-method-destroy'> /**
  887. </span> * Destroys the surface. This is done by removing all components from it and
  888. * also removing its reference to a DOM element.
  889. *
  890. * For example:
  891. *
  892. * drawComponent.surface.destroy();
  893. */
  894. destroy: function() {
  895. var me = this;
  896. delete me.domRef;
  897. if (me.background) {
  898. me.background.destroy();
  899. }
  900. me.removeAll(true);
  901. Ext.destroy(me.groups.items);
  902. }
  903. });
  904. </pre>
  905. </body>
  906. </html>