Radar.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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-chart-series-Radar'>/**
  19. </span> * @class Ext.chart.series.Radar
  20. *
  21. * Creates a Radar Chart. A Radar Chart is a useful visualization technique for comparing different quantitative values for
  22. * a constrained number of categories.
  23. *
  24. * As with all other series, the Radar series must be appended in the *series* Chart array configuration. See the Chart
  25. * documentation for more information. A typical configuration object for the radar series could be:
  26. *
  27. * @example
  28. * var store = Ext.create('Ext.data.JsonStore', {
  29. * fields: ['name', 'data1', 'data2', 'data3'],
  30. * data: [
  31. * { 'name': 'metric one', 'data1': 14, 'data2': 12, 'data3': 13 },
  32. * { 'name': 'metric two', 'data1': 16, 'data2': 8, 'data3': 3 },
  33. * { 'name': 'metric three', 'data1': 14, 'data2': 2, 'data3': 7 },
  34. * { 'name': 'metric four', 'data1': 6, 'data2': 14, 'data3': 23 },
  35. * { 'name': 'metric five', 'data1': 36, 'data2': 38, 'data3': 33 }
  36. * ]
  37. * });
  38. *
  39. * Ext.create('Ext.chart.Chart', {
  40. * renderTo: Ext.getBody(),
  41. * width: 500,
  42. * height: 300,
  43. * animate: true,
  44. * theme:'Category2',
  45. * store: store,
  46. * axes: [{
  47. * type: 'Radial',
  48. * position: 'radial',
  49. * label: {
  50. * display: true
  51. * }
  52. * }],
  53. * series: [{
  54. * type: 'radar',
  55. * xField: 'name',
  56. * yField: 'data1',
  57. * showInLegend: true,
  58. * showMarkers: true,
  59. * markerConfig: {
  60. * radius: 5,
  61. * size: 5
  62. * },
  63. * style: {
  64. * 'stroke-width': 2,
  65. * fill: 'none'
  66. * }
  67. * },{
  68. * type: 'radar',
  69. * xField: 'name',
  70. * yField: 'data2',
  71. * showMarkers: true,
  72. * showInLegend: true,
  73. * markerConfig: {
  74. * radius: 5,
  75. * size: 5
  76. * },
  77. * style: {
  78. * 'stroke-width': 2,
  79. * fill: 'none'
  80. * }
  81. * },{
  82. * type: 'radar',
  83. * xField: 'name',
  84. * yField: 'data3',
  85. * showMarkers: true,
  86. * showInLegend: true,
  87. * markerConfig: {
  88. * radius: 5,
  89. * size: 5
  90. * },
  91. * style: {
  92. * 'stroke-width': 2,
  93. * fill: 'none'
  94. * }
  95. * }]
  96. * });
  97. *
  98. * In this configuration we add three series to the chart. Each of these series is bound to the same
  99. * categories field, `name` but bound to different properties for each category, `data1`, `data2` and
  100. * `data3` respectively. All series display markers by having `showMarkers` enabled. The configuration
  101. * for the markers of each series can be set by adding properties onto the markerConfig object.
  102. * Finally we override some theme styling properties by adding properties to the `style` object.
  103. *
  104. * @xtype radar
  105. */
  106. Ext.define('Ext.chart.series.Radar', {
  107. /* Begin Definitions */
  108. extend: 'Ext.chart.series.Series',
  109. requires: ['Ext.chart.Shape', 'Ext.fx.Anim'],
  110. /* End Definitions */
  111. type: &quot;radar&quot;,
  112. alias: 'series.radar',
  113. rad: Math.PI / 180,
  114. showInLegend: false,
  115. <span id='Ext-chart-series-Radar-cfg-style'> /**
  116. </span> * @cfg {Object} style
  117. * An object containing styles for overriding series styles from Theming.
  118. */
  119. style: {},
  120. constructor: function(config) {
  121. this.callParent(arguments);
  122. var me = this,
  123. surface = me.chart.surface, i, l;
  124. me.group = surface.getGroup(me.seriesId);
  125. if (me.showMarkers) {
  126. me.markerGroup = surface.getGroup(me.seriesId + '-markers');
  127. }
  128. },
  129. <span id='Ext-chart-series-Radar-method-drawSeries'> /**
  130. </span> * Draws the series for the current chart.
  131. */
  132. drawSeries: function() {
  133. var me = this,
  134. store = me.chart.getChartStore(),
  135. data = store.data.items,
  136. d, record,
  137. group = me.group,
  138. sprite,
  139. chart = me.chart,
  140. seriesItems = chart.series.items,
  141. s, sLen, series,
  142. animate = chart.animate,
  143. field = me.field || me.yField,
  144. surface = chart.surface,
  145. chartBBox = chart.chartBBox,
  146. seriesIdx = me.seriesIdx,
  147. colorArrayStyle = me.colorArrayStyle,
  148. centerX, centerY,
  149. items,
  150. radius,
  151. maxValue = 0,
  152. fields = [],
  153. max = Math.max,
  154. cos = Math.cos,
  155. sin = Math.sin,
  156. pi2 = Math.PI * 2,
  157. l = store.getCount(),
  158. startPath, path, x, y, rho,
  159. i, nfields,
  160. seriesStyle = me.seriesStyle,
  161. seriesLabelStyle = me.seriesLabelStyle,
  162. first = chart.resizing || !me.radar,
  163. axis = chart.axes &amp;&amp; chart.axes.get(0),
  164. aggregate = !(axis &amp;&amp; axis.maximum);
  165. me.setBBox();
  166. maxValue = aggregate? 0 : (axis.maximum || 0);
  167. Ext.apply(seriesStyle, me.style || {});
  168. //if the store is empty then there's nothing to draw
  169. if (!store || !store.getCount() || me.seriesIsHidden) {
  170. me.hide();
  171. me.items = [];
  172. if (me.radar) {
  173. me.radar.hide(true);
  174. }
  175. me.radar = null;
  176. return;
  177. }
  178. if(!seriesStyle['stroke']){
  179. seriesStyle['stroke'] = colorArrayStyle[seriesIdx % colorArrayStyle.length];
  180. }
  181. me.unHighlightItem();
  182. me.cleanHighlights();
  183. centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
  184. centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
  185. me.radius = radius = Math.min(chartBBox.width, chartBBox.height) /2;
  186. me.items = items = [];
  187. if (aggregate) {
  188. //get all renderer fields
  189. for (s = 0, sLen = seriesItems.length; s &lt; sLen; s++) {
  190. series = seriesItems[s];
  191. fields.push(series.yField);
  192. }
  193. //get maxValue to interpolate
  194. for (d = 0; d &lt; l; d++) {
  195. record = data[d];
  196. for (i = 0, nfields = fields.length; i &lt; nfields; i++) {
  197. maxValue = max(+record.get(fields[i]), maxValue);
  198. }
  199. }
  200. }
  201. //ensure non-zero value.
  202. maxValue = maxValue || 1;
  203. //create path and items
  204. startPath = []; path = [];
  205. for (i = 0; i &lt; l; i++) {
  206. record = data[i];
  207. rho = radius * record.get(field) / maxValue;
  208. x = rho * cos(i / l * pi2);
  209. y = rho * sin(i / l * pi2);
  210. if (i == 0) {
  211. path.push('M', x + centerX, y + centerY);
  212. startPath.push('M', 0.01 * x + centerX, 0.01 * y + centerY);
  213. } else {
  214. path.push('L', x + centerX, y + centerY);
  215. startPath.push('L', 0.01 * x + centerX, 0.01 * y + centerY);
  216. }
  217. items.push({
  218. sprite: false, //TODO(nico): add markers
  219. point: [centerX + x, centerY + y],
  220. storeItem: record,
  221. series: me
  222. });
  223. }
  224. path.push('Z');
  225. //create path sprite
  226. if (!me.radar) {
  227. me.radar = surface.add(Ext.apply({
  228. type: 'path',
  229. group: group,
  230. path: startPath
  231. }, seriesStyle || {}));
  232. }
  233. //reset on resizing
  234. if (chart.resizing) {
  235. me.radar.setAttributes({
  236. path: startPath
  237. }, true);
  238. }
  239. //render/animate
  240. if (chart.animate) {
  241. me.onAnimate(me.radar, {
  242. to: Ext.apply({
  243. path: path
  244. }, seriesStyle || {})
  245. });
  246. } else {
  247. me.radar.setAttributes(Ext.apply({
  248. path: path
  249. }, seriesStyle || {}), true);
  250. }
  251. //render markers, labels and callouts
  252. if (me.showMarkers) {
  253. me.drawMarkers();
  254. }
  255. me.renderLabels();
  256. me.renderCallouts();
  257. },
  258. // @private draws the markers for the lines (if any).
  259. drawMarkers: function() {
  260. var me = this,
  261. chart = me.chart,
  262. surface = chart.surface,
  263. markerStyle = Ext.apply({}, me.markerStyle || {}),
  264. endMarkerStyle = Ext.apply(markerStyle, me.markerConfig, {
  265. fill: me.colorArrayStyle[me.seriesIdx % me.colorArrayStyle.length]
  266. }),
  267. items = me.items,
  268. type = endMarkerStyle.type,
  269. markerGroup = me.markerGroup,
  270. centerX = me.centerX,
  271. centerY = me.centerY,
  272. item, i, l, marker;
  273. delete endMarkerStyle.type;
  274. for (i = 0, l = items.length; i &lt; l; i++) {
  275. item = items[i];
  276. marker = markerGroup.getAt(i);
  277. if (!marker) {
  278. marker = Ext.chart.Shape[type](surface, Ext.apply({
  279. group: markerGroup,
  280. x: 0,
  281. y: 0,
  282. translate: {
  283. x: centerX,
  284. y: centerY
  285. }
  286. }, endMarkerStyle));
  287. }
  288. else {
  289. marker.show();
  290. }
  291. item.sprite = marker;
  292. if (chart.resizing) {
  293. marker.setAttributes({
  294. x: 0,
  295. y: 0,
  296. translate: {
  297. x: centerX,
  298. y: centerY
  299. }
  300. }, true);
  301. }
  302. marker._to = {
  303. translate: {
  304. x: item.point[0],
  305. y: item.point[1]
  306. }
  307. };
  308. //render/animate
  309. if (chart.animate) {
  310. me.onAnimate(marker, {
  311. to: marker._to
  312. });
  313. }
  314. else {
  315. marker.setAttributes(Ext.apply(marker._to, endMarkerStyle || {}), true);
  316. }
  317. }
  318. },
  319. isItemInPoint: function(x, y, item) {
  320. var point,
  321. tolerance = 10,
  322. abs = Math.abs;
  323. point = item.point;
  324. return (abs(point[0] - x) &lt;= tolerance &amp;&amp;
  325. abs(point[1] - y) &lt;= tolerance);
  326. },
  327. // @private callback for when creating a label sprite.
  328. onCreateLabel: function(storeItem, item, i, display) {
  329. var me = this,
  330. group = me.labelsGroup,
  331. config = me.label,
  332. centerX = me.centerX,
  333. centerY = me.centerY,
  334. point = item.point,
  335. endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config);
  336. return me.chart.surface.add(Ext.apply({
  337. 'type': 'text',
  338. 'text-anchor': 'middle',
  339. 'group': group,
  340. 'x': centerX,
  341. 'y': centerY
  342. }, config || {}));
  343. },
  344. // @private callback for when placing a label sprite.
  345. onPlaceLabel: function(label, storeItem, item, i, display, animate) {
  346. var me = this,
  347. chart = me.chart,
  348. resizing = chart.resizing,
  349. config = me.label,
  350. format = config.renderer,
  351. field = config.field,
  352. centerX = me.centerX,
  353. centerY = me.centerY,
  354. opt = {
  355. x: item.point[0],
  356. y: item.point[1]
  357. },
  358. x = opt.x - centerX,
  359. y = opt.y - centerY;
  360. label.setAttributes({
  361. text: format(storeItem.get(field)),
  362. hidden: true
  363. },
  364. true);
  365. if (resizing) {
  366. label.setAttributes({
  367. x: centerX,
  368. y: centerY
  369. }, true);
  370. }
  371. if (animate) {
  372. label.show(true);
  373. me.onAnimate(label, {
  374. to: opt
  375. });
  376. } else {
  377. label.setAttributes(opt, true);
  378. label.show(true);
  379. }
  380. },
  381. // @private for toggling (show/hide) series.
  382. toggleAll: function(show) {
  383. var me = this,
  384. i, ln, shadow, shadows;
  385. if (!show) {
  386. Ext.chart.series.Radar.superclass.hideAll.call(me);
  387. }
  388. else {
  389. Ext.chart.series.Radar.superclass.showAll.call(me);
  390. }
  391. if (me.radar) {
  392. me.radar.setAttributes({
  393. hidden: !show
  394. }, true);
  395. //hide shadows too
  396. if (me.radar.shadows) {
  397. for (i = 0, shadows = me.radar.shadows, ln = shadows.length; i &lt; ln; i++) {
  398. shadow = shadows[i];
  399. shadow.setAttributes({
  400. hidden: !show
  401. }, true);
  402. }
  403. }
  404. }
  405. },
  406. // @private hide all elements in the series.
  407. hideAll: function() {
  408. this.toggleAll(false);
  409. this.hideMarkers(0);
  410. },
  411. // @private show all elements in the series.
  412. showAll: function() {
  413. this.toggleAll(true);
  414. },
  415. // @private hide all markers that belong to `markerGroup`
  416. hideMarkers: function(index) {
  417. var me = this,
  418. count = me.markerGroup &amp;&amp; me.markerGroup.getCount() || 0,
  419. i = index || 0;
  420. for (; i &lt; count; i++) {
  421. me.markerGroup.getAt(i).hide(true);
  422. }
  423. }
  424. });
  425. </pre>
  426. </body>
  427. </html>