Svg.html 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  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-engine-Svg'>/**
  19. </span> * Provides specific methods to draw with SVG.
  20. */
  21. Ext.define('Ext.draw.engine.Svg', {
  22. /* Begin Definitions */
  23. extend: 'Ext.draw.Surface',
  24. requires: ['Ext.draw.Draw', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],
  25. /* End Definitions */
  26. engine: 'Svg',
  27. trimRe: /^\s+|\s+$/g,
  28. spacesRe: /\s+/,
  29. xlink: &quot;http:/&quot; + &quot;/www.w3.org/1999/xlink&quot;,
  30. translateAttrs: {
  31. radius: &quot;r&quot;,
  32. radiusX: &quot;rx&quot;,
  33. radiusY: &quot;ry&quot;,
  34. path: &quot;d&quot;,
  35. lineWidth: &quot;stroke-width&quot;,
  36. fillOpacity: &quot;fill-opacity&quot;,
  37. strokeOpacity: &quot;stroke-opacity&quot;,
  38. strokeLinejoin: &quot;stroke-linejoin&quot;
  39. },
  40. parsers: {},
  41. minDefaults: {
  42. circle: {
  43. cx: 0,
  44. cy: 0,
  45. r: 0,
  46. fill: &quot;none&quot;,
  47. stroke: null,
  48. &quot;stroke-width&quot;: null,
  49. opacity: null,
  50. &quot;fill-opacity&quot;: null,
  51. &quot;stroke-opacity&quot;: null
  52. },
  53. ellipse: {
  54. cx: 0,
  55. cy: 0,
  56. rx: 0,
  57. ry: 0,
  58. fill: &quot;none&quot;,
  59. stroke: null,
  60. &quot;stroke-width&quot;: null,
  61. opacity: null,
  62. &quot;fill-opacity&quot;: null,
  63. &quot;stroke-opacity&quot;: null
  64. },
  65. rect: {
  66. x: 0,
  67. y: 0,
  68. width: 0,
  69. height: 0,
  70. rx: 0,
  71. ry: 0,
  72. fill: &quot;none&quot;,
  73. stroke: null,
  74. &quot;stroke-width&quot;: null,
  75. opacity: null,
  76. &quot;fill-opacity&quot;: null,
  77. &quot;stroke-opacity&quot;: null
  78. },
  79. text: {
  80. x: 0,
  81. y: 0,
  82. &quot;text-anchor&quot;: &quot;start&quot;,
  83. &quot;font-family&quot;: null,
  84. &quot;font-size&quot;: null,
  85. &quot;font-weight&quot;: null,
  86. &quot;font-style&quot;: null,
  87. fill: &quot;#000&quot;,
  88. stroke: null,
  89. &quot;stroke-width&quot;: null,
  90. opacity: null,
  91. &quot;fill-opacity&quot;: null,
  92. &quot;stroke-opacity&quot;: null
  93. },
  94. path: {
  95. d: &quot;M0,0&quot;,
  96. fill: &quot;none&quot;,
  97. stroke: null,
  98. &quot;stroke-width&quot;: null,
  99. opacity: null,
  100. &quot;fill-opacity&quot;: null,
  101. &quot;stroke-opacity&quot;: null
  102. },
  103. image: {
  104. x: 0,
  105. y: 0,
  106. width: 0,
  107. height: 0,
  108. preserveAspectRatio: &quot;none&quot;,
  109. opacity: null
  110. }
  111. },
  112. createSvgElement: function(type, attrs) {
  113. var el = this.domRef.createElementNS(&quot;http:/&quot; + &quot;/www.w3.org/2000/svg&quot;, type),
  114. key;
  115. if (attrs) {
  116. for (key in attrs) {
  117. el.setAttribute(key, String(attrs[key]));
  118. }
  119. }
  120. return el;
  121. },
  122. createSpriteElement: function(sprite) {
  123. // Create svg element and append to the DOM.
  124. var el = this.createSvgElement(sprite.type);
  125. el.id = sprite.id;
  126. if (el.style) {
  127. el.style.webkitTapHighlightColor = &quot;rgba(0,0,0,0)&quot;;
  128. }
  129. sprite.el = Ext.get(el);
  130. this.applyZIndex(sprite); //performs the insertion
  131. sprite.matrix = new Ext.draw.Matrix();
  132. sprite.bbox = {
  133. plain: 0,
  134. transform: 0
  135. };
  136. this.applyAttrs(sprite);
  137. this.applyTransformations(sprite);
  138. sprite.fireEvent(&quot;render&quot;, sprite);
  139. return el;
  140. },
  141. getBBoxText: function (sprite) {
  142. var bbox = {},
  143. bb, height, width, i, ln, el;
  144. if (sprite &amp;&amp; sprite.el) {
  145. el = sprite.el.dom;
  146. try {
  147. bbox = el.getBBox();
  148. return bbox;
  149. } catch(e) {
  150. // Firefox 3.0.x plays badly here
  151. }
  152. bbox = {x: bbox.x, y: Infinity, width: 0, height: 0};
  153. ln = el.getNumberOfChars();
  154. for (i = 0; i &lt; ln; i++) {
  155. bb = el.getExtentOfChar(i);
  156. bbox.y = Math.min(bb.y, bbox.y);
  157. height = bb.y + bb.height - bbox.y;
  158. bbox.height = Math.max(bbox.height, height);
  159. width = bb.x + bb.width - bbox.x;
  160. bbox.width = Math.max(bbox.width, width);
  161. }
  162. return bbox;
  163. }
  164. },
  165. hide: function() {
  166. Ext.get(this.el).hide();
  167. },
  168. show: function() {
  169. Ext.get(this.el).show();
  170. },
  171. hidePrim: function(sprite) {
  172. this.addCls(sprite, Ext.baseCSSPrefix + 'hide-visibility');
  173. },
  174. showPrim: function(sprite) {
  175. this.removeCls(sprite, Ext.baseCSSPrefix + 'hide-visibility');
  176. },
  177. getDefs: function() {
  178. return this._defs || (this._defs = this.createSvgElement(&quot;defs&quot;));
  179. },
  180. transform: function(sprite, matrixOnly) {
  181. var me = this,
  182. matrix = new Ext.draw.Matrix(),
  183. transforms = sprite.transformations,
  184. transformsLength = transforms.length,
  185. i = 0,
  186. transform, type;
  187. for (; i &lt; transformsLength; i++) {
  188. transform = transforms[i];
  189. type = transform.type;
  190. if (type == &quot;translate&quot;) {
  191. matrix.translate(transform.x, transform.y);
  192. }
  193. else if (type == &quot;rotate&quot;) {
  194. matrix.rotate(transform.degrees, transform.x, transform.y);
  195. }
  196. else if (type == &quot;scale&quot;) {
  197. matrix.scale(transform.x, transform.y, transform.centerX, transform.centerY);
  198. }
  199. }
  200. sprite.matrix = matrix;
  201. if (!matrixOnly) {
  202. sprite.el.set({transform: matrix.toSvg()});
  203. }
  204. },
  205. setSize: function(width, height) {
  206. var me = this,
  207. el = me.el;
  208. width = +width || me.width;
  209. height = +height || me.height;
  210. me.width = width;
  211. me.height = height;
  212. el.setSize(width, height);
  213. el.set({
  214. width: width,
  215. height: height
  216. });
  217. me.callParent([width, height]);
  218. },
  219. <span id='Ext-draw-engine-Svg-method-getRegion'> /**
  220. </span> * Get the region for the surface's canvas area
  221. * @returns {Ext.util.Region}
  222. */
  223. getRegion: function() {
  224. // Mozilla requires using the background rect because the svg element returns an
  225. // incorrect region. Webkit gives no region for the rect and must use the svg element.
  226. var svgXY = this.el.getXY(),
  227. rectXY = this.bgRect.getXY(),
  228. max = Math.max,
  229. x = max(svgXY[0], rectXY[0]),
  230. y = max(svgXY[1], rectXY[1]);
  231. return {
  232. left: x,
  233. top: y,
  234. right: x + this.width,
  235. bottom: y + this.height
  236. };
  237. },
  238. onRemove: function(sprite) {
  239. if (sprite.el) {
  240. sprite.el.destroy();
  241. delete sprite.el;
  242. }
  243. this.callParent(arguments);
  244. },
  245. setViewBox: function(x, y, width, height) {
  246. if (isFinite(x) &amp;&amp; isFinite(y) &amp;&amp; isFinite(width) &amp;&amp; isFinite(height)) {
  247. this.callParent(arguments);
  248. this.el.dom.setAttribute(&quot;viewBox&quot;, [x, y, width, height].join(&quot; &quot;));
  249. }
  250. },
  251. render: function (container) {
  252. var me = this,
  253. width,
  254. height,
  255. el,
  256. defs,
  257. bgRect,
  258. webkitRect;
  259. if (!me.el) {
  260. width = me.width || 0;
  261. height = me.height || 0;
  262. el = me.createSvgElement('svg', {
  263. xmlns: &quot;http:/&quot; + &quot;/www.w3.org/2000/svg&quot;,
  264. version: 1.1,
  265. width: width,
  266. height: height
  267. });
  268. defs = me.getDefs();
  269. // Create a rect that is always the same size as the svg root; this serves 2 purposes:
  270. // (1) It allows mouse events to be fired over empty areas in Webkit, and (2) we can
  271. // use it rather than the svg element for retrieving the correct client rect of the
  272. // surface in Mozilla (see https://bugzilla.mozilla.org/show_bug.cgi?id=530985)
  273. bgRect = me.createSvgElement(&quot;rect&quot;, {
  274. width: &quot;100%&quot;,
  275. height: &quot;100%&quot;,
  276. fill: &quot;#000&quot;,
  277. stroke: &quot;none&quot;,
  278. opacity: 0
  279. });
  280. if (Ext.isSafari3) {
  281. // Rect that we will show/hide to fix old WebKit bug with rendering issues.
  282. webkitRect = me.createSvgElement(&quot;rect&quot;, {
  283. x: -10,
  284. y: -10,
  285. width: &quot;110%&quot;,
  286. height: &quot;110%&quot;,
  287. fill: &quot;none&quot;,
  288. stroke: &quot;#000&quot;
  289. });
  290. }
  291. el.appendChild(defs);
  292. if (Ext.isSafari3) {
  293. el.appendChild(webkitRect);
  294. }
  295. el.appendChild(bgRect);
  296. container.appendChild(el);
  297. me.el = Ext.get(el);
  298. me.bgRect = Ext.get(bgRect);
  299. if (Ext.isSafari3) {
  300. me.webkitRect = Ext.get(webkitRect);
  301. me.webkitRect.hide();
  302. }
  303. me.el.on({
  304. scope: me,
  305. mouseup: me.onMouseUp,
  306. mousedown: me.onMouseDown,
  307. mouseover: me.onMouseOver,
  308. mouseout: me.onMouseOut,
  309. mousemove: me.onMouseMove,
  310. mouseenter: me.onMouseEnter,
  311. mouseleave: me.onMouseLeave,
  312. click: me.onClick,
  313. dblclick: me.onDblClick
  314. });
  315. }
  316. me.renderAll();
  317. },
  318. // private
  319. onMouseEnter: function(e) {
  320. if (this.el.parent().getRegion().contains(e.getPoint())) {
  321. this.fireEvent('mouseenter', e);
  322. }
  323. },
  324. // private
  325. onMouseLeave: function(e) {
  326. if (!this.el.parent().getRegion().contains(e.getPoint())) {
  327. this.fireEvent('mouseleave', e);
  328. }
  329. },
  330. // @private - Normalize a delegated single event from the main container to each sprite and sprite group
  331. processEvent: function(name, e) {
  332. var target = e.getTarget(),
  333. surface = this.surface,
  334. sprite;
  335. this.fireEvent(name, e);
  336. // We wrap text types in a tspan, sprite is the parent.
  337. if (target.nodeName == &quot;tspan&quot; &amp;&amp; target.parentNode) {
  338. target = target.parentNode;
  339. }
  340. sprite = this.items.get(target.id);
  341. if (sprite) {
  342. sprite.fireEvent(name, sprite, e);
  343. }
  344. },
  345. /* @private - Wrap SVG text inside a tspan to allow for line wrapping. In addition this normallizes
  346. * the baseline for text the vertical middle of the text to be the same as VML.
  347. */
  348. tuneText: function (sprite, attrs) {
  349. var el = sprite.el.dom,
  350. tspans = [],
  351. height, tspan, text, i, ln, texts, factor, x;
  352. if (attrs.hasOwnProperty(&quot;text&quot;)) {
  353. //only create new tspans for text lines if the text has been
  354. //updated or if it's the first time we're setting the text
  355. //into the sprite.
  356. //get the actual rendered text.
  357. text = sprite.tspans &amp;&amp; Ext.Array.map(sprite.tspans, function(t) { return t.textContent; }).join('');
  358. if (!sprite.tspans || attrs.text != text) {
  359. tspans = this.setText(sprite, attrs.text);
  360. sprite.tspans = tspans;
  361. //for all other cases reuse the tspans previously created.
  362. } else {
  363. tspans = sprite.tspans || [];
  364. }
  365. }
  366. // Normalize baseline via a DY shift of first tspan. Shift other rows by height * line height (1.2)
  367. if (tspans.length) {
  368. height = this.getBBoxText(sprite).height;
  369. x = sprite.el.dom.getAttribute(&quot;x&quot;);
  370. for (i = 0, ln = tspans.length; i &lt; ln; i++) {
  371. // The text baseline for FireFox 3.0 and 3.5 is different than other SVG implementations
  372. // so we are going to normalize that here
  373. factor = (Ext.isFF3_0 || Ext.isFF3_5) ? 2 : 4;
  374. tspans[i].setAttribute(&quot;x&quot;, x);
  375. tspans[i].setAttribute(&quot;dy&quot;, i ? height * 1.2 : height / factor);
  376. }
  377. sprite.dirty = true;
  378. }
  379. },
  380. setText: function(sprite, textString) {
  381. var me = this,
  382. el = sprite.el.dom,
  383. tspans = [],
  384. height, tspan, text, i, ln, texts;
  385. while (el.firstChild) {
  386. el.removeChild(el.firstChild);
  387. }
  388. // Wrap each row into tspan to emulate rows
  389. texts = String(textString).split(&quot;\n&quot;);
  390. for (i = 0, ln = texts.length; i &lt; ln; i++) {
  391. text = texts[i];
  392. if (text) {
  393. tspan = me.createSvgElement(&quot;tspan&quot;);
  394. tspan.appendChild(document.createTextNode(Ext.htmlDecode(text)));
  395. el.appendChild(tspan);
  396. tspans[i] = tspan;
  397. }
  398. }
  399. return tspans;
  400. },
  401. renderAll: function() {
  402. this.items.each(this.renderItem, this);
  403. },
  404. renderItem: function (sprite) {
  405. if (!this.el) {
  406. return;
  407. }
  408. if (!sprite.el) {
  409. this.createSpriteElement(sprite);
  410. }
  411. if (sprite.zIndexDirty) {
  412. this.applyZIndex(sprite);
  413. }
  414. if (sprite.dirty) {
  415. this.applyAttrs(sprite);
  416. if (sprite.dirtyTransform) {
  417. this.applyTransformations(sprite);
  418. }
  419. }
  420. },
  421. redraw: function(sprite) {
  422. sprite.dirty = sprite.zIndexDirty = true;
  423. this.renderItem(sprite);
  424. },
  425. applyAttrs: function (sprite) {
  426. var me = this,
  427. el = sprite.el,
  428. group = sprite.group,
  429. sattr = sprite.attr,
  430. parsers = me.parsers,
  431. //Safari does not handle linear gradients correctly in quirksmode
  432. //ref: https://bugs.webkit.org/show_bug.cgi?id=41952
  433. //ref: EXTJSIV-1472
  434. gradientsMap = me.gradientsMap || {},
  435. safariFix = Ext.isSafari &amp;&amp; !Ext.isStrict,
  436. groups, i, ln, attrs, font, key, style, name, rect;
  437. if (group) {
  438. groups = [].concat(group);
  439. ln = groups.length;
  440. for (i = 0; i &lt; ln; i++) {
  441. group = groups[i];
  442. me.getGroup(group).add(sprite);
  443. }
  444. delete sprite.group;
  445. }
  446. attrs = me.scrubAttrs(sprite) || {};
  447. // if (sprite.dirtyPath) {
  448. sprite.bbox.plain = 0;
  449. sprite.bbox.transform = 0;
  450. if (sprite.type == &quot;circle&quot; || sprite.type == &quot;ellipse&quot;) {
  451. attrs.cx = attrs.cx || attrs.x;
  452. attrs.cy = attrs.cy || attrs.y;
  453. }
  454. else if (sprite.type == &quot;rect&quot;) {
  455. attrs.rx = attrs.ry = attrs.r;
  456. }
  457. else if (sprite.type == &quot;path&quot; &amp;&amp; attrs.d) {
  458. attrs.d = Ext.draw.Draw.pathToString(Ext.draw.Draw.pathToAbsolute(attrs.d));
  459. }
  460. sprite.dirtyPath = false;
  461. // }
  462. // else {
  463. // delete attrs.d;
  464. // }
  465. if (attrs['clip-rect']) {
  466. me.setClip(sprite, attrs);
  467. delete attrs['clip-rect'];
  468. }
  469. if (sprite.type == 'text' &amp;&amp; attrs.font &amp;&amp; sprite.dirtyFont) {
  470. el.set({ style: &quot;font: &quot; + attrs.font});
  471. }
  472. if (sprite.type == &quot;image&quot;) {
  473. el.dom.setAttributeNS(me.xlink, &quot;href&quot;, attrs.src);
  474. }
  475. Ext.applyIf(attrs, me.minDefaults[sprite.type]);
  476. if (sprite.dirtyHidden) {
  477. (sattr.hidden) ? me.hidePrim(sprite) : me.showPrim(sprite);
  478. sprite.dirtyHidden = false;
  479. }
  480. for (key in attrs) {
  481. if (attrs.hasOwnProperty(key) &amp;&amp; attrs[key] != null) {
  482. //Safari does not handle linear gradients correctly in quirksmode
  483. //ref: https://bugs.webkit.org/show_bug.cgi?id=41952
  484. //ref: EXTJSIV-1472
  485. //if we're Safari in QuirksMode and we're applying some color attribute and the value of that
  486. //attribute is a reference to a gradient then assign a plain color to that value instead of the gradient.
  487. if (safariFix &amp;&amp; ('color|stroke|fill'.indexOf(key) &gt; -1) &amp;&amp; (attrs[key] in gradientsMap)) {
  488. attrs[key] = gradientsMap[attrs[key]];
  489. }
  490. //hidden is not a proper SVG attribute.
  491. if (key == 'hidden' &amp;&amp; sprite.type == 'text') {
  492. continue;
  493. }
  494. if (key in parsers) {
  495. el.dom.setAttribute(key, parsers[key](attrs[key], sprite, me));
  496. } else {
  497. el.dom.setAttribute(key, attrs[key]);
  498. }
  499. }
  500. }
  501. if (sprite.type == 'text') {
  502. me.tuneText(sprite, attrs);
  503. }
  504. sprite.dirtyFont = false;
  505. //set styles
  506. style = sattr.style;
  507. if (style) {
  508. el.setStyle(style);
  509. }
  510. sprite.dirty = false;
  511. if (Ext.isSafari3) {
  512. // Refreshing the view to fix bug EXTJSIV-1: rendering issue in old Safari 3
  513. me.webkitRect.show();
  514. setTimeout(function () {
  515. me.webkitRect.hide();
  516. });
  517. }
  518. },
  519. setClip: function(sprite, params) {
  520. var me = this,
  521. rect = params[&quot;clip-rect&quot;],
  522. clipEl, clipPath;
  523. if (rect) {
  524. if (sprite.clip) {
  525. sprite.clip.parentNode.parentNode.removeChild(sprite.clip.parentNode);
  526. }
  527. clipEl = me.createSvgElement('clipPath');
  528. clipPath = me.createSvgElement('rect');
  529. clipEl.id = Ext.id(null, 'ext-clip-');
  530. clipPath.setAttribute(&quot;x&quot;, rect.x);
  531. clipPath.setAttribute(&quot;y&quot;, rect.y);
  532. clipPath.setAttribute(&quot;width&quot;, rect.width);
  533. clipPath.setAttribute(&quot;height&quot;, rect.height);
  534. clipEl.appendChild(clipPath);
  535. me.getDefs().appendChild(clipEl);
  536. sprite.el.dom.setAttribute(&quot;clip-path&quot;, &quot;url(#&quot; + clipEl.id + &quot;)&quot;);
  537. sprite.clip = clipPath;
  538. }
  539. // if (!attrs[key]) {
  540. // var clip = Ext.getDoc().dom.getElementById(sprite.el.getAttribute(&quot;clip-path&quot;).replace(/(^url\(#|\)$)/g, &quot;&quot;));
  541. // clip &amp;&amp; clip.parentNode.removeChild(clip);
  542. // sprite.el.setAttribute(&quot;clip-path&quot;, &quot;&quot;);
  543. // delete attrss.clip;
  544. // }
  545. },
  546. <span id='Ext-draw-engine-Svg-method-applyZIndex'> /**
  547. </span> * Insert or move a given sprite's element to the correct place in the DOM list for its zIndex
  548. * @param {Ext.draw.Sprite} sprite
  549. */
  550. applyZIndex: function(sprite) {
  551. var me = this,
  552. items = me.items,
  553. idx = items.indexOf(sprite),
  554. el = sprite.el,
  555. prevEl;
  556. if (me.el.dom.childNodes[idx + 2] !== el.dom) { //shift by 2 to account for defs and bg rect
  557. if (idx &gt; 0) {
  558. // Find the first previous sprite which has its DOM element created already
  559. do {
  560. prevEl = items.getAt(--idx).el;
  561. } while (!prevEl &amp;&amp; idx &gt; 0);
  562. }
  563. el.insertAfter(prevEl || me.bgRect);
  564. }
  565. sprite.zIndexDirty = false;
  566. },
  567. createItem: function (config) {
  568. var sprite = new Ext.draw.Sprite(config);
  569. sprite.surface = this;
  570. return sprite;
  571. },
  572. addGradient: function(gradient) {
  573. gradient = Ext.draw.Draw.parseGradient(gradient);
  574. var me = this,
  575. ln = gradient.stops.length,
  576. vector = gradient.vector,
  577. //Safari does not handle linear gradients correctly in quirksmode
  578. //ref: https://bugs.webkit.org/show_bug.cgi?id=41952
  579. //ref: EXTJSIV-1472
  580. usePlain = Ext.isSafari &amp;&amp; !Ext.isStrict,
  581. gradientEl, stop, stopEl, i, gradientsMap;
  582. gradientsMap = me.gradientsMap || {};
  583. if (!usePlain) {
  584. if (gradient.type == &quot;linear&quot;) {
  585. gradientEl = me.createSvgElement(&quot;linearGradient&quot;);
  586. gradientEl.setAttribute(&quot;x1&quot;, vector[0]);
  587. gradientEl.setAttribute(&quot;y1&quot;, vector[1]);
  588. gradientEl.setAttribute(&quot;x2&quot;, vector[2]);
  589. gradientEl.setAttribute(&quot;y2&quot;, vector[3]);
  590. }
  591. else {
  592. gradientEl = me.createSvgElement(&quot;radialGradient&quot;);
  593. gradientEl.setAttribute(&quot;cx&quot;, gradient.centerX);
  594. gradientEl.setAttribute(&quot;cy&quot;, gradient.centerY);
  595. gradientEl.setAttribute(&quot;r&quot;, gradient.radius);
  596. if (Ext.isNumber(gradient.focalX) &amp;&amp; Ext.isNumber(gradient.focalY)) {
  597. gradientEl.setAttribute(&quot;fx&quot;, gradient.focalX);
  598. gradientEl.setAttribute(&quot;fy&quot;, gradient.focalY);
  599. }
  600. }
  601. gradientEl.id = gradient.id;
  602. me.getDefs().appendChild(gradientEl);
  603. for (i = 0; i &lt; ln; i++) {
  604. stop = gradient.stops[i];
  605. stopEl = me.createSvgElement(&quot;stop&quot;);
  606. stopEl.setAttribute(&quot;offset&quot;, stop.offset + &quot;%&quot;);
  607. stopEl.setAttribute(&quot;stop-color&quot;, stop.color);
  608. stopEl.setAttribute(&quot;stop-opacity&quot;,stop.opacity);
  609. gradientEl.appendChild(stopEl);
  610. }
  611. } else {
  612. gradientsMap['url(#' + gradient.id + ')'] = gradient.stops[0].color;
  613. }
  614. me.gradientsMap = gradientsMap;
  615. },
  616. <span id='Ext-draw-engine-Svg-method-hasCls'> /**
  617. </span> * Checks if the specified CSS class exists on this element's DOM node.
  618. * @param {Ext.draw.Sprite} sprite The sprite to look into.
  619. * @param {String} className The CSS class to check for
  620. * @return {Boolean} True if the class exists, else false
  621. */
  622. hasCls: function(sprite, className) {
  623. return className &amp;&amp; (' ' + (sprite.el.dom.getAttribute('class') || '') + ' ').indexOf(' ' + className + ' ') != -1;
  624. },
  625. addCls: function(sprite, className) {
  626. var el = sprite.el,
  627. i,
  628. len,
  629. v,
  630. cls = [],
  631. curCls = el.getAttribute('class') || '';
  632. // Separate case is for speed
  633. if (!Ext.isArray(className)) {
  634. if (typeof className == 'string' &amp;&amp; !this.hasCls(sprite, className)) {
  635. el.set({ 'class': curCls + ' ' + className });
  636. }
  637. }
  638. else {
  639. for (i = 0, len = className.length; i &lt; len; i++) {
  640. v = className[i];
  641. if (typeof v == 'string' &amp;&amp; (' ' + curCls + ' ').indexOf(' ' + v + ' ') == -1) {
  642. cls.push(v);
  643. }
  644. }
  645. if (cls.length) {
  646. el.set({ 'class': ' ' + cls.join(' ') });
  647. }
  648. }
  649. },
  650. removeCls: function(sprite, className) {
  651. var me = this,
  652. el = sprite.el,
  653. curCls = el.getAttribute('class') || '',
  654. i, idx, len, cls, elClasses;
  655. if (!Ext.isArray(className)){
  656. className = [className];
  657. }
  658. if (curCls) {
  659. elClasses = curCls.replace(me.trimRe, ' ').split(me.spacesRe);
  660. for (i = 0, len = className.length; i &lt; len; i++) {
  661. cls = className[i];
  662. if (typeof cls == 'string') {
  663. cls = cls.replace(me.trimRe, '');
  664. idx = Ext.Array.indexOf(elClasses, cls);
  665. if (idx != -1) {
  666. Ext.Array.erase(elClasses, idx, 1);
  667. }
  668. }
  669. }
  670. el.set({ 'class': elClasses.join(' ') });
  671. }
  672. },
  673. destroy: function() {
  674. var me = this;
  675. me.callParent();
  676. if (me.el) {
  677. me.el.remove();
  678. }
  679. if (me._defs) {
  680. Ext.get(me._defs).destroy();
  681. }
  682. if (me.bgRect) {
  683. Ext.get(me.bgRect).destroy();
  684. }
  685. if (me.webkitRect) {
  686. Ext.get(me.webkitRect).destroy();
  687. }
  688. delete me.el;
  689. }
  690. });
  691. </pre>
  692. </body>
  693. </html>