Vml.html 31 KB

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