/ext-4.0.7/docs/source/Vml.html

https://bitbucket.org/srogerf/javascript · HTML · 963 lines · 875 code · 88 blank · 0 comment · 0 complexity · fd6bd3633651427987f31f8277c0fb20 MD5 · raw file

  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-Vml'>/**
  19. </span> * @class Ext.draw.engine.Vml
  20. * @extends Ext.draw.Surface
  21. * Provides specific methods to draw with VML.
  22. */
  23. Ext.define('Ext.draw.engine.Vml', {
  24. /* Begin Definitions */
  25. extend: 'Ext.draw.Surface',
  26. requires: ['Ext.draw.Draw', 'Ext.draw.Color', 'Ext.draw.Sprite', 'Ext.draw.Matrix', 'Ext.Element'],
  27. /* End Definitions */
  28. engine: 'Vml',
  29. map: {M: &quot;m&quot;, L: &quot;l&quot;, C: &quot;c&quot;, Z: &quot;x&quot;, m: &quot;t&quot;, l: &quot;r&quot;, c: &quot;v&quot;, z: &quot;x&quot;},
  30. bitesRe: /([clmz]),?([^clmz]*)/gi,
  31. valRe: /-?[^,\s-]+/g,
  32. fillUrlRe: /^url\(\s*['&quot;]?([^\)]+?)['&quot;]?\s*\)$/i,
  33. pathlike: /^(path|rect)$/,
  34. NonVmlPathRe: /[ahqstv]/ig, // Non-VML Pathing ops
  35. partialPathRe: /[clmz]/g,
  36. fontFamilyRe: /^['&quot;]+|['&quot;]+$/g,
  37. baseVmlCls: Ext.baseCSSPrefix + 'vml-base',
  38. vmlGroupCls: Ext.baseCSSPrefix + 'vml-group',
  39. spriteCls: Ext.baseCSSPrefix + 'vml-sprite',
  40. measureSpanCls: Ext.baseCSSPrefix + 'vml-measure-span',
  41. zoom: 21600,
  42. coordsize: 1000,
  43. coordorigin: '0 0',
  44. // VML uses CSS z-index and therefore doesn't need sprites to be kept in zIndex order
  45. orderSpritesByZIndex: false,
  46. // @private
  47. // Convert an SVG standard path into a VML path
  48. path2vml: function (path) {
  49. var me = this,
  50. nonVML = me.NonVmlPathRe,
  51. map = me.map,
  52. val = me.valRe,
  53. zoom = me.zoom,
  54. bites = me.bitesRe,
  55. command = Ext.Function.bind(Ext.draw.Draw.pathToAbsolute, Ext.draw.Draw),
  56. res, pa, p, r, i, ii, j, jj;
  57. if (String(path).match(nonVML)) {
  58. command = Ext.Function.bind(Ext.draw.Draw.path2curve, Ext.draw.Draw);
  59. } else if (!String(path).match(me.partialPathRe)) {
  60. res = String(path).replace(bites, function (all, command, args) {
  61. var vals = [],
  62. isMove = command.toLowerCase() == &quot;m&quot;,
  63. res = map[command];
  64. args.replace(val, function (value) {
  65. if (isMove &amp;&amp; vals[length] == 2) {
  66. res += vals + map[command == &quot;m&quot; ? &quot;l&quot; : &quot;L&quot;];
  67. vals = [];
  68. }
  69. vals.push(Math.round(value * zoom));
  70. });
  71. return res + vals;
  72. });
  73. return res;
  74. }
  75. pa = command(path);
  76. res = [];
  77. for (i = 0, ii = pa.length; i &lt; ii; i++) {
  78. p = pa[i];
  79. r = pa[i][0].toLowerCase();
  80. if (r == &quot;z&quot;) {
  81. r = &quot;x&quot;;
  82. }
  83. for (j = 1, jj = p.length; j &lt; jj; j++) {
  84. r += Math.round(p[j] * me.zoom) + (j != jj - 1 ? &quot;,&quot; : &quot;&quot;);
  85. }
  86. res.push(r);
  87. }
  88. return res.join(&quot; &quot;);
  89. },
  90. // @private - set of attributes which need to be translated from the sprite API to the native browser API
  91. translateAttrs: {
  92. radius: &quot;r&quot;,
  93. radiusX: &quot;rx&quot;,
  94. radiusY: &quot;ry&quot;,
  95. lineWidth: &quot;stroke-width&quot;,
  96. fillOpacity: &quot;fill-opacity&quot;,
  97. strokeOpacity: &quot;stroke-opacity&quot;,
  98. strokeLinejoin: &quot;stroke-linejoin&quot;
  99. },
  100. // @private - Minimun set of defaults for different types of sprites.
  101. minDefaults: {
  102. circle: {
  103. fill: &quot;none&quot;,
  104. stroke: null,
  105. &quot;stroke-width&quot;: null,
  106. opacity: null,
  107. &quot;fill-opacity&quot;: null,
  108. &quot;stroke-opacity&quot;: null
  109. },
  110. ellipse: {
  111. cx: 0,
  112. cy: 0,
  113. rx: 0,
  114. ry: 0,
  115. fill: &quot;none&quot;,
  116. stroke: null,
  117. &quot;stroke-width&quot;: null,
  118. opacity: null,
  119. &quot;fill-opacity&quot;: null,
  120. &quot;stroke-opacity&quot;: null
  121. },
  122. rect: {
  123. x: 0,
  124. y: 0,
  125. width: 0,
  126. height: 0,
  127. rx: 0,
  128. ry: 0,
  129. fill: &quot;none&quot;,
  130. stroke: null,
  131. &quot;stroke-width&quot;: null,
  132. opacity: null,
  133. &quot;fill-opacity&quot;: null,
  134. &quot;stroke-opacity&quot;: null
  135. },
  136. text: {
  137. x: 0,
  138. y: 0,
  139. &quot;text-anchor&quot;: &quot;start&quot;,
  140. font: '10px &quot;Arial&quot;',
  141. fill: &quot;#000&quot;,
  142. stroke: null,
  143. &quot;stroke-width&quot;: null,
  144. opacity: null,
  145. &quot;fill-opacity&quot;: null,
  146. &quot;stroke-opacity&quot;: null
  147. },
  148. path: {
  149. d: &quot;M0,0&quot;,
  150. fill: &quot;none&quot;,
  151. stroke: null,
  152. &quot;stroke-width&quot;: null,
  153. opacity: null,
  154. &quot;fill-opacity&quot;: null,
  155. &quot;stroke-opacity&quot;: null
  156. },
  157. image: {
  158. x: 0,
  159. y: 0,
  160. width: 0,
  161. height: 0,
  162. preserveAspectRatio: &quot;none&quot;,
  163. opacity: null
  164. }
  165. },
  166. // private
  167. onMouseEnter: function(e) {
  168. this.fireEvent(&quot;mouseenter&quot;, e);
  169. },
  170. // private
  171. onMouseLeave: function(e) {
  172. this.fireEvent(&quot;mouseleave&quot;, e);
  173. },
  174. // @private - Normalize a delegated single event from the main container to each sprite and sprite group
  175. processEvent: function(name, e) {
  176. var target = e.getTarget(),
  177. surface = this.surface,
  178. sprite;
  179. this.fireEvent(name, e);
  180. sprite = this.items.get(target.id);
  181. if (sprite) {
  182. sprite.fireEvent(name, sprite, e);
  183. }
  184. },
  185. // Create the VML element/elements and append them to the DOM
  186. createSpriteElement: function(sprite) {
  187. var me = this,
  188. attr = sprite.attr,
  189. type = sprite.type,
  190. zoom = me.zoom,
  191. vml = sprite.vml || (sprite.vml = {}),
  192. round = Math.round,
  193. el = me.createNode('shape'),
  194. path, skew, textPath;
  195. el.coordsize = zoom + ' ' + zoom;
  196. el.coordorigin = attr.coordorigin || &quot;0 0&quot;;
  197. Ext.get(el).addCls(me.spriteCls);
  198. if (type == &quot;text&quot;) {
  199. vml.path = path = me.createNode(&quot;path&quot;);
  200. path.textpathok = true;
  201. vml.textpath = textPath = me.createNode(&quot;textpath&quot;);
  202. textPath.on = true;
  203. el.appendChild(textPath);
  204. el.appendChild(path);
  205. }
  206. el.id = sprite.id;
  207. sprite.el = Ext.get(el);
  208. me.el.appendChild(el);
  209. if (type !== 'image') {
  210. skew = me.createNode(&quot;skew&quot;);
  211. skew.on = true;
  212. el.appendChild(skew);
  213. sprite.skew = skew;
  214. }
  215. sprite.matrix = Ext.create('Ext.draw.Matrix');
  216. sprite.bbox = {
  217. plain: null,
  218. transform: null
  219. };
  220. sprite.fireEvent(&quot;render&quot;, sprite);
  221. return sprite.el;
  222. },
  223. // @private - Get bounding box for the sprite. The Sprite itself has the public method.
  224. getBBox: function (sprite, isWithoutTransform) {
  225. var realPath = this[&quot;getPath&quot; + sprite.type](sprite);
  226. if (isWithoutTransform) {
  227. sprite.bbox.plain = sprite.bbox.plain || Ext.draw.Draw.pathDimensions(realPath);
  228. return sprite.bbox.plain;
  229. }
  230. sprite.bbox.transform = sprite.bbox.transform || Ext.draw.Draw.pathDimensions(Ext.draw.Draw.mapPath(realPath, sprite.matrix));
  231. return sprite.bbox.transform;
  232. },
  233. getBBoxText: function (sprite) {
  234. var vml = sprite.vml;
  235. return {
  236. x: vml.X + (vml.bbx || 0) - vml.W / 2,
  237. y: vml.Y - vml.H / 2,
  238. width: vml.W,
  239. height: vml.H
  240. };
  241. },
  242. applyAttrs: function (sprite) {
  243. var me = this,
  244. vml = sprite.vml,
  245. group = sprite.group,
  246. spriteAttr = sprite.attr,
  247. el = sprite.el,
  248. dom = el.dom,
  249. style, name, groups, i, ln, scrubbedAttrs, font, key, bbox;
  250. if (group) {
  251. groups = [].concat(group);
  252. ln = groups.length;
  253. for (i = 0; i &lt; ln; i++) {
  254. group = groups[i];
  255. me.getGroup(group).add(sprite);
  256. }
  257. delete sprite.group;
  258. }
  259. scrubbedAttrs = me.scrubAttrs(sprite) || {};
  260. if (sprite.zIndexDirty) {
  261. me.setZIndex(sprite);
  262. }
  263. // Apply minimum default attributes
  264. Ext.applyIf(scrubbedAttrs, me.minDefaults[sprite.type]);
  265. if (dom.href) {
  266. dom.href = scrubbedAttrs.href;
  267. }
  268. if (dom.title) {
  269. dom.title = scrubbedAttrs.title;
  270. }
  271. if (dom.target) {
  272. dom.target = scrubbedAttrs.target;
  273. }
  274. if (dom.cursor) {
  275. dom.cursor = scrubbedAttrs.cursor;
  276. }
  277. // Change visibility
  278. if (sprite.dirtyHidden) {
  279. (scrubbedAttrs.hidden) ? me.hidePrim(sprite) : me.showPrim(sprite);
  280. sprite.dirtyHidden = false;
  281. }
  282. // Update path
  283. if (sprite.dirtyPath) {
  284. if (sprite.type == &quot;circle&quot; || sprite.type == &quot;ellipse&quot;) {
  285. var cx = scrubbedAttrs.x,
  286. cy = scrubbedAttrs.y,
  287. rx = scrubbedAttrs.rx || scrubbedAttrs.r || 0,
  288. ry = scrubbedAttrs.ry || scrubbedAttrs.r || 0;
  289. dom.path = Ext.String.format(&quot;ar{0},{1},{2},{3},{4},{1},{4},{1}&quot;,
  290. Math.round((cx - rx) * me.zoom),
  291. Math.round((cy - ry) * me.zoom),
  292. Math.round((cx + rx) * me.zoom),
  293. Math.round((cy + ry) * me.zoom),
  294. Math.round(cx * me.zoom));
  295. sprite.dirtyPath = false;
  296. }
  297. else if (sprite.type !== &quot;text&quot;) {
  298. sprite.attr.path = scrubbedAttrs.path = me.setPaths(sprite, scrubbedAttrs) || scrubbedAttrs.path;
  299. dom.path = me.path2vml(scrubbedAttrs.path);
  300. sprite.dirtyPath = false;
  301. }
  302. }
  303. // Apply clipping
  304. if (&quot;clip-rect&quot; in scrubbedAttrs) {
  305. me.setClip(sprite, scrubbedAttrs);
  306. }
  307. // Handle text (special handling required)
  308. if (sprite.type == &quot;text&quot;) {
  309. me.setTextAttributes(sprite, scrubbedAttrs);
  310. }
  311. // Handle fill and opacity
  312. if (sprite.type == 'image' || scrubbedAttrs.opacity || scrubbedAttrs['fill-opacity'] || scrubbedAttrs.fill) {
  313. me.setFill(sprite, scrubbedAttrs);
  314. }
  315. // Handle stroke (all fills require a stroke element)
  316. if (scrubbedAttrs.stroke || scrubbedAttrs['stroke-opacity'] || scrubbedAttrs.fill) {
  317. me.setStroke(sprite, scrubbedAttrs);
  318. }
  319. //set styles
  320. style = spriteAttr.style;
  321. if (style) {
  322. el.setStyle(style);
  323. }
  324. sprite.dirty = false;
  325. },
  326. setZIndex: function(sprite) {
  327. if (sprite.el) {
  328. if (sprite.attr.zIndex != undefined) {
  329. sprite.el.setStyle('zIndex', sprite.attr.zIndex);
  330. }
  331. sprite.zIndexDirty = false;
  332. }
  333. },
  334. // Normalize all virtualized types into paths.
  335. setPaths: function(sprite, params) {
  336. var spriteAttr = sprite.attr;
  337. // Clear bbox cache
  338. sprite.bbox.plain = null;
  339. sprite.bbox.transform = null;
  340. if (sprite.type == 'circle') {
  341. spriteAttr.rx = spriteAttr.ry = params.r;
  342. return Ext.draw.Draw.ellipsePath(sprite);
  343. }
  344. else if (sprite.type == 'ellipse') {
  345. spriteAttr.rx = params.rx;
  346. spriteAttr.ry = params.ry;
  347. return Ext.draw.Draw.ellipsePath(sprite);
  348. }
  349. else if (sprite.type == 'rect' || sprite.type == 'image') {
  350. spriteAttr.rx = spriteAttr.ry = params.r;
  351. return Ext.draw.Draw.rectPath(sprite);
  352. }
  353. else if (sprite.type == 'path' &amp;&amp; spriteAttr.path) {
  354. return Ext.draw.Draw.pathToAbsolute(spriteAttr.path);
  355. }
  356. return false;
  357. },
  358. setFill: function(sprite, params) {
  359. var me = this,
  360. el = sprite.el,
  361. dom = el.dom,
  362. fillEl = dom.getElementsByTagName('fill')[0],
  363. opacity, gradient, fillUrl, rotation, angle;
  364. if (fillEl) {
  365. dom.removeChild(fillEl);
  366. } else {
  367. fillEl = me.createNode('fill');
  368. }
  369. if (Ext.isArray(params.fill)) {
  370. params.fill = params.fill[0];
  371. }
  372. if (sprite.type == 'image') {
  373. fillEl.on = true;
  374. fillEl.src = params.src;
  375. fillEl.type = &quot;tile&quot;;
  376. fillEl.rotate = true;
  377. } else if (params.fill == &quot;none&quot;) {
  378. fillEl.on = false;
  379. } else {
  380. if (typeof params.opacity == &quot;number&quot;) {
  381. fillEl.opacity = params.opacity;
  382. }
  383. if (typeof params[&quot;fill-opacity&quot;] == &quot;number&quot;) {
  384. fillEl.opacity = params[&quot;fill-opacity&quot;];
  385. }
  386. fillEl.on = true;
  387. if (typeof params.fill == &quot;string&quot;) {
  388. fillUrl = params.fill.match(me.fillUrlRe);
  389. if (fillUrl) {
  390. fillUrl = fillUrl[1];
  391. // If the URL matches one of the registered gradients, render that gradient
  392. if (fillUrl.charAt(0) == &quot;#&quot;) {
  393. gradient = me.gradientsColl.getByKey(fillUrl.substring(1));
  394. }
  395. if (gradient) {
  396. // VML angle is offset and inverted from standard, and must be adjusted to match rotation transform
  397. rotation = params.rotation;
  398. angle = -(gradient.angle + 270 + (rotation ? rotation.degrees : 0)) % 360;
  399. // IE will flip the angle at 0 degrees...
  400. if (angle === 0) {
  401. angle = 180;
  402. }
  403. fillEl.angle = angle;
  404. fillEl.type = &quot;gradient&quot;;
  405. fillEl.method = &quot;sigma&quot;;
  406. fillEl.colors = gradient.colors;
  407. }
  408. // Otherwise treat it as an image
  409. else {
  410. fillEl.src = fillUrl;
  411. fillEl.type = &quot;tile&quot;;
  412. fillEl.rotate = true;
  413. }
  414. }
  415. else {
  416. fillEl.color = Ext.draw.Color.toHex(params.fill) || params.fill;
  417. fillEl.src = &quot;&quot;;
  418. fillEl.type = &quot;solid&quot;;
  419. }
  420. }
  421. }
  422. dom.appendChild(fillEl);
  423. },
  424. setStroke: function(sprite, params) {
  425. var me = this,
  426. el = sprite.el.dom,
  427. strokeEl = sprite.strokeEl,
  428. newStroke = false,
  429. width, opacity;
  430. if (!strokeEl) {
  431. strokeEl = sprite.strokeEl = me.createNode(&quot;stroke&quot;);
  432. newStroke = true;
  433. }
  434. if (Ext.isArray(params.stroke)) {
  435. params.stroke = params.stroke[0];
  436. }
  437. if (!params.stroke || params.stroke == &quot;none&quot; || params.stroke == 0 || params[&quot;stroke-width&quot;] == 0) {
  438. strokeEl.on = false;
  439. }
  440. else {
  441. strokeEl.on = true;
  442. if (params.stroke &amp;&amp; !params.stroke.match(me.fillUrlRe)) {
  443. // VML does NOT support a gradient stroke :(
  444. strokeEl.color = Ext.draw.Color.toHex(params.stroke);
  445. }
  446. strokeEl.joinstyle = params[&quot;stroke-linejoin&quot;];
  447. strokeEl.endcap = params[&quot;stroke-linecap&quot;] || &quot;round&quot;;
  448. strokeEl.miterlimit = params[&quot;stroke-miterlimit&quot;] || 8;
  449. width = parseFloat(params[&quot;stroke-width&quot;] || 1) * 0.75;
  450. opacity = params[&quot;stroke-opacity&quot;] || 1;
  451. // VML Does not support stroke widths under 1, so we're going to fiddle with stroke-opacity instead.
  452. if (Ext.isNumber(width) &amp;&amp; width &lt; 1) {
  453. strokeEl.weight = 1;
  454. strokeEl.opacity = opacity * width;
  455. }
  456. else {
  457. strokeEl.weight = width;
  458. strokeEl.opacity = opacity;
  459. }
  460. }
  461. if (newStroke) {
  462. el.appendChild(strokeEl);
  463. }
  464. },
  465. setClip: function(sprite, params) {
  466. var me = this,
  467. el = sprite.el,
  468. clipEl = sprite.clipEl,
  469. rect = String(params[&quot;clip-rect&quot;]).split(me.separatorRe);
  470. if (!clipEl) {
  471. clipEl = sprite.clipEl = me.el.insertFirst(Ext.getDoc().dom.createElement(&quot;div&quot;));
  472. clipEl.addCls(Ext.baseCSSPrefix + 'vml-sprite');
  473. }
  474. if (rect.length == 4) {
  475. rect[2] = +rect[2] + (+rect[0]);
  476. rect[3] = +rect[3] + (+rect[1]);
  477. clipEl.setStyle(&quot;clip&quot;, Ext.String.format(&quot;rect({1}px {2}px {3}px {0}px)&quot;, rect[0], rect[1], rect[2], rect[3]));
  478. clipEl.setSize(me.el.width, me.el.height);
  479. }
  480. else {
  481. clipEl.setStyle(&quot;clip&quot;, &quot;&quot;);
  482. }
  483. },
  484. setTextAttributes: function(sprite, params) {
  485. var me = this,
  486. vml = sprite.vml,
  487. textStyle = vml.textpath.style,
  488. spanCacheStyle = me.span.style,
  489. zoom = me.zoom,
  490. round = Math.round,
  491. fontObj = {
  492. fontSize: &quot;font-size&quot;,
  493. fontWeight: &quot;font-weight&quot;,
  494. fontStyle: &quot;font-style&quot;
  495. },
  496. fontProp,
  497. paramProp;
  498. if (sprite.dirtyFont) {
  499. if (params.font) {
  500. textStyle.font = spanCacheStyle.font = params.font;
  501. }
  502. if (params[&quot;font-family&quot;]) {
  503. textStyle.fontFamily = '&quot;' + params[&quot;font-family&quot;].split(&quot;,&quot;)[0].replace(me.fontFamilyRe, &quot;&quot;) + '&quot;';
  504. spanCacheStyle.fontFamily = params[&quot;font-family&quot;];
  505. }
  506. for (fontProp in fontObj) {
  507. paramProp = params[fontObj[fontProp]];
  508. if (paramProp) {
  509. textStyle[fontProp] = spanCacheStyle[fontProp] = paramProp;
  510. }
  511. }
  512. me.setText(sprite, params.text);
  513. if (vml.textpath.string) {
  514. me.span.innerHTML = String(vml.textpath.string).replace(/&lt;/g, &quot;&amp;#60;&quot;).replace(/&amp;/g, &quot;&amp;#38;&quot;).replace(/\n/g, &quot;&lt;br&gt;&quot;);
  515. }
  516. vml.W = me.span.offsetWidth;
  517. vml.H = me.span.offsetHeight + 2; // TODO handle baseline differences and offset in VML Textpath
  518. // text-anchor emulation
  519. if (params[&quot;text-anchor&quot;] == &quot;middle&quot;) {
  520. textStyle[&quot;v-text-align&quot;] = &quot;center&quot;;
  521. }
  522. else if (params[&quot;text-anchor&quot;] == &quot;end&quot;) {
  523. textStyle[&quot;v-text-align&quot;] = &quot;right&quot;;
  524. vml.bbx = -Math.round(vml.W / 2);
  525. }
  526. else {
  527. textStyle[&quot;v-text-align&quot;] = &quot;left&quot;;
  528. vml.bbx = Math.round(vml.W / 2);
  529. }
  530. }
  531. vml.X = params.x;
  532. vml.Y = params.y;
  533. vml.path.v = Ext.String.format(&quot;m{0},{1}l{2},{1}&quot;, Math.round(vml.X * zoom), Math.round(vml.Y * zoom), Math.round(vml.X * zoom) + 1);
  534. // Clear bbox cache
  535. sprite.bbox.plain = null;
  536. sprite.bbox.transform = null;
  537. sprite.dirtyFont = false;
  538. },
  539. setText: function(sprite, text) {
  540. sprite.vml.textpath.string = Ext.htmlDecode(text);
  541. },
  542. hide: function() {
  543. this.el.hide();
  544. },
  545. show: function() {
  546. this.el.show();
  547. },
  548. hidePrim: function(sprite) {
  549. sprite.el.addCls(Ext.baseCSSPrefix + 'hide-visibility');
  550. },
  551. showPrim: function(sprite) {
  552. sprite.el.removeCls(Ext.baseCSSPrefix + 'hide-visibility');
  553. },
  554. setSize: function(width, height) {
  555. var me = this;
  556. width = width || me.width;
  557. height = height || me.height;
  558. me.width = width;
  559. me.height = height;
  560. if (me.el) {
  561. // Size outer div
  562. if (width != undefined) {
  563. me.el.setWidth(width);
  564. }
  565. if (height != undefined) {
  566. me.el.setHeight(height);
  567. }
  568. // Handle viewBox sizing
  569. me.applyViewBox();
  570. me.callParent(arguments);
  571. }
  572. },
  573. setViewBox: function(x, y, width, height) {
  574. this.callParent(arguments);
  575. this.viewBox = {
  576. x: x,
  577. y: y,
  578. width: width,
  579. height: height
  580. };
  581. this.applyViewBox();
  582. },
  583. <span id='Ext-draw-engine-Vml-method-applyViewBox'> /**
  584. </span> * @private Using the current viewBox property and the surface's width and height, calculate the
  585. * appropriate viewBoxShift that will be applied as a persistent transform to all sprites.
  586. */
  587. applyViewBox: function() {
  588. var me = this,
  589. viewBox = me.viewBox,
  590. width = me.width,
  591. height = me.height,
  592. viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight,
  593. relativeHeight, relativeWidth, size;
  594. if (viewBox &amp;&amp; (width || height)) {
  595. viewBoxX = viewBox.x;
  596. viewBoxY = viewBox.y;
  597. viewBoxWidth = viewBox.width;
  598. viewBoxHeight = viewBox.height;
  599. relativeHeight = height / viewBoxHeight;
  600. relativeWidth = width / viewBoxWidth;
  601. if (viewBoxWidth * relativeHeight &lt; width) {
  602. viewBoxX -= (width - viewBoxWidth * relativeHeight) / 2 / relativeHeight;
  603. }
  604. if (viewBoxHeight * relativeWidth &lt; height) {
  605. viewBoxY -= (height - viewBoxHeight * relativeWidth) / 2 / relativeWidth;
  606. }
  607. size = 1 / Math.max(viewBoxWidth / width, viewBoxHeight / height);
  608. me.viewBoxShift = {
  609. dx: -viewBoxX,
  610. dy: -viewBoxY,
  611. scale: size
  612. };
  613. me.items.each(function(item) {
  614. me.transform(item);
  615. });
  616. }
  617. },
  618. onAdd: function(item) {
  619. this.callParent(arguments);
  620. if (this.el) {
  621. this.renderItem(item);
  622. }
  623. },
  624. onRemove: function(sprite) {
  625. if (sprite.el) {
  626. sprite.el.remove();
  627. delete sprite.el;
  628. }
  629. this.callParent(arguments);
  630. },
  631. // VML Node factory method (createNode)
  632. createNode : (function () {
  633. try {
  634. var doc = Ext.getDoc().dom;
  635. if (!doc.namespaces.rvml) {
  636. doc.namespaces.add(&quot;rvml&quot;, &quot;urn:schemas-microsoft-com:vml&quot;);
  637. }
  638. return function (tagName) {
  639. return doc.createElement(&quot;&lt;rvml:&quot; + tagName + ' class=&quot;rvml&quot;&gt;');
  640. };
  641. } catch (e) {
  642. return function (tagName) {
  643. return doc.createElement(&quot;&lt;&quot; + tagName + ' xmlns=&quot;urn:schemas-microsoft.com:vml&quot; class=&quot;rvml&quot;&gt;');
  644. };
  645. }
  646. })(),
  647. render: function (container) {
  648. var me = this,
  649. doc = Ext.getDoc().dom;
  650. if (!me.el) {
  651. var el = doc.createElement(&quot;div&quot;);
  652. me.el = Ext.get(el);
  653. me.el.addCls(me.baseVmlCls);
  654. // Measuring span (offscrren)
  655. me.span = doc.createElement(&quot;span&quot;);
  656. Ext.get(me.span).addCls(me.measureSpanCls);
  657. el.appendChild(me.span);
  658. me.el.setSize(me.width || 10, me.height || 10);
  659. container.appendChild(el);
  660. me.el.on({
  661. scope: me,
  662. mouseup: me.onMouseUp,
  663. mousedown: me.onMouseDown,
  664. mouseover: me.onMouseOver,
  665. mouseout: me.onMouseOut,
  666. mousemove: me.onMouseMove,
  667. mouseenter: me.onMouseEnter,
  668. mouseleave: me.onMouseLeave,
  669. click: me.onClick
  670. });
  671. }
  672. me.renderAll();
  673. },
  674. renderAll: function() {
  675. this.items.each(this.renderItem, this);
  676. },
  677. redraw: function(sprite) {
  678. sprite.dirty = true;
  679. this.renderItem(sprite);
  680. },
  681. renderItem: function (sprite) {
  682. // Does the surface element exist?
  683. if (!this.el) {
  684. return;
  685. }
  686. // Create sprite element if necessary
  687. if (!sprite.el) {
  688. this.createSpriteElement(sprite);
  689. }
  690. if (sprite.dirty) {
  691. this.applyAttrs(sprite);
  692. if (sprite.dirtyTransform) {
  693. this.applyTransformations(sprite);
  694. }
  695. }
  696. },
  697. rotationCompensation: function (deg, dx, dy) {
  698. var matrix = Ext.create('Ext.draw.Matrix');
  699. matrix.rotate(-deg, 0.5, 0.5);
  700. return {
  701. x: matrix.x(dx, dy),
  702. y: matrix.y(dx, dy)
  703. };
  704. },
  705. extractTransform: function (sprite) {
  706. var me = this,
  707. matrix = Ext.create('Ext.draw.Matrix'), scale,
  708. transformstions, tranformationsLength,
  709. transform, i = 0,
  710. shift = me.viewBoxShift;
  711. for(transformstions = sprite.transformations, tranformationsLength = transformstions.length;
  712. i &lt; tranformationsLength; i ++) {
  713. transform = transformstions[i];
  714. switch (transform.type) {
  715. case 'translate' :
  716. matrix.translate(transform.x, transform.y);
  717. break;
  718. case 'rotate':
  719. matrix.rotate(transform.degrees, transform.x, transform.y);
  720. break;
  721. case 'scale':
  722. matrix.scale(transform.x || transform.scale, transform.y || transform.scale, transform.centerX, transform.centerY);
  723. break;
  724. }
  725. }
  726. if (shift) {
  727. matrix.add(1, 0, 0, 1, shift.dx, shift.dy);
  728. matrix.prepend(shift.scale, 0, 0, shift.scale, 0, 0);
  729. }
  730. return sprite.matrix = matrix;
  731. },
  732. setSimpleCoords: function(sprite, sx, sy, dx, dy, rotate) {
  733. var me = this,
  734. matrix = sprite.matrix,
  735. dom = sprite.el.dom,
  736. style = dom.style,
  737. yFlipper = 1,
  738. flip = &quot;&quot;,
  739. fill = dom.getElementsByTagName('fill')[0],
  740. kx = me.zoom / sx,
  741. ky = me.zoom / sy,
  742. rotationCompensation;
  743. if (!sx || !sy) {
  744. return;
  745. }
  746. dom.coordsize = Math.abs(kx) + ' ' + Math.abs(ky);
  747. style.rotation = rotate * (sx * sy &lt; 0 ? -1 : 1);
  748. if (rotate) {
  749. rotationCompensation = me.rotationCompensation(rotate, dx, dy);
  750. dx = rotationCompensation.x;
  751. dy = rotationCompensation.y;
  752. }
  753. if (sx &lt; 0) {
  754. flip += &quot;x&quot;
  755. }
  756. if (sy &lt; 0) {
  757. flip += &quot; y&quot;;
  758. yFlipper = -1;
  759. }
  760. style.flip = flip;
  761. dom.coordorigin = (dx * -kx) + ' ' + (dy * -ky);
  762. if (fill) {
  763. dom.removeChild(fill);
  764. rotationCompensation = me.rotationCompensation(rotate, matrix.x(sprite.x, sprite.y), matrix.y(sprite.x, sprite.y));
  765. fill.position = rotationCompensation.x * yFlipper + ' ' + rotationCompensation.y * yFlipper;
  766. fill.size = sprite.width * Math.abs(sx) + ' ' + sprite.height * Math.abs(sy);
  767. dom.appendChild(fill);
  768. }
  769. },
  770. transform : function (sprite) {
  771. var me = this,
  772. el = sprite.el,
  773. skew = sprite.skew,
  774. dom = el.dom,
  775. domStyle = dom.style,
  776. matrix = me.extractTransform(sprite).clone(),
  777. split, zoom = me.zoom,
  778. fill = dom.getElementsByTagName('fill')[0],
  779. isPatt = !String(sprite.fill).indexOf(&quot;url(&quot;),
  780. offset, c;
  781. // Hide element while we transform
  782. if (sprite.type != &quot;image&quot; &amp;&amp; skew &amp;&amp; !isPatt) {
  783. // matrix transform via VML skew
  784. skew.matrix = matrix.toString();
  785. // skew.offset = '32767,1' OK
  786. // skew.offset = '32768,1' Crash
  787. // M$, R U kidding??
  788. offset = matrix.offset();
  789. if (offset[0] &gt; 32767) {
  790. offset[0] = 32767;
  791. } else if (offset[0] &lt; -32768) {
  792. offset[0] = -32768
  793. }
  794. if (offset[1] &gt; 32767) {
  795. offset[1] = 32767;
  796. } else if (offset[1] &lt; -32768) {
  797. offset[1] = -32768
  798. }
  799. skew.offset = offset;
  800. } else {
  801. if (skew) {
  802. skew.matrix = &quot;1 0 0 1&quot;;
  803. skew.offset = &quot;0 0&quot;;
  804. }
  805. split = matrix.split();
  806. if (split.isSimple) {
  807. domStyle.filter = '';
  808. me.setSimpleCoords(sprite, split.scaleX, split.scaleY, split.translateX, split.translateY, split.rotate / Math.PI * 180);
  809. } else {
  810. domStyle.filter = matrix.toFilter();
  811. var bb = me.getBBox(sprite),
  812. dx = bb.x - sprite.x,
  813. dy = bb.y - sprite.y;
  814. dom.coordorigin = (dx * -zoom) + ' ' + (dy * -zoom);
  815. if (fill) {
  816. dom.removeChild(fill);
  817. fill.position = dx + ' ' + dy;
  818. fill.size = sprite.width * sprite.scale.x + ' ' + sprite.height * 1.1;
  819. dom.appendChild(fill);
  820. }
  821. }
  822. }
  823. },
  824. createItem: function (config) {
  825. return Ext.create('Ext.draw.Sprite', config);
  826. },
  827. getRegion: function() {
  828. return this.el.getRegion();
  829. },
  830. addCls: function(sprite, className) {
  831. if (sprite &amp;&amp; sprite.el) {
  832. sprite.el.addCls(className);
  833. }
  834. },
  835. removeCls: function(sprite, className) {
  836. if (sprite &amp;&amp; sprite.el) {
  837. sprite.el.removeCls(className);
  838. }
  839. },
  840. <span id='Ext-draw-engine-Vml-method-addGradient'> /**
  841. </span> * Adds a definition to this Surface for a linear gradient. We convert the gradient definition
  842. * to its corresponding VML attributes and store it for later use by individual sprites.
  843. * @param {Object} gradient
  844. */
  845. addGradient: function(gradient) {
  846. var gradients = this.gradientsColl || (this.gradientsColl = Ext.create('Ext.util.MixedCollection')),
  847. colors = [],
  848. stops = Ext.create('Ext.util.MixedCollection');
  849. // Build colors string
  850. stops.addAll(gradient.stops);
  851. stops.sortByKey(&quot;ASC&quot;, function(a, b) {
  852. a = parseInt(a, 10);
  853. b = parseInt(b, 10);
  854. return a &gt; b ? 1 : (a &lt; b ? -1 : 0);
  855. });
  856. stops.eachKey(function(k, v) {
  857. colors.push(k + &quot;% &quot; + v.color);
  858. });
  859. gradients.add(gradient.id, {
  860. colors: colors.join(&quot;,&quot;),
  861. angle: gradient.angle
  862. });
  863. },
  864. destroy: function() {
  865. var me = this;
  866. me.callParent(arguments);
  867. if (me.el) {
  868. me.el.remove();
  869. }
  870. delete me.el;
  871. }
  872. });
  873. </pre>
  874. </body>
  875. </html>