cc18054248e4fd06c758e498a6ef600df746c004.svn-base 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. /**
  2. * echarts图表类:漏斗图
  3. *
  4. * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
  5. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  6. *
  7. */
  8. define(function (require) {
  9. var ChartBase = require('./base');
  10. // 图形依赖
  11. var TextShape = require('zrender/shape/Text');
  12. var LineShape = require('zrender/shape/Line');
  13. var PolygonShape = require('zrender/shape/Polygon');
  14. var ecConfig = require('../config');
  15. // 漏斗图默认参数
  16. ecConfig.funnel = {
  17. zlevel: 0, // 一级层叠
  18. z: 2, // 二级层叠
  19. clickable: true,
  20. legendHoverLink: true,
  21. x: 80,
  22. y: 60,
  23. x2: 80,
  24. y2: 60,
  25. // width: {totalWidth} - x - x2,
  26. // height: {totalHeight} - y - y2,
  27. min: 0,
  28. max: 100,
  29. minSize: '0%',
  30. maxSize: '100%',
  31. sort: 'descending', // 'ascending', 'descending'
  32. gap: 0,
  33. funnelAlign: 'center',
  34. itemStyle: {
  35. normal: {
  36. // color: 各异,
  37. borderColor: '#fff',
  38. borderWidth: 1,
  39. label: {
  40. show: true,
  41. position: 'outer'
  42. // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
  43. // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
  44. },
  45. labelLine: {
  46. show: true,
  47. length: 10,
  48. lineStyle: {
  49. // color: 各异,
  50. width: 1,
  51. type: 'solid'
  52. }
  53. }
  54. },
  55. emphasis: {
  56. // color: 各异,
  57. borderColor: 'rgba(0,0,0,0)',
  58. borderWidth: 1,
  59. label: {
  60. show: true
  61. },
  62. labelLine: {
  63. show: true
  64. }
  65. }
  66. }
  67. };
  68. var ecData = require('../util/ecData');
  69. var number = require('../util/number');
  70. var zrUtil = require('zrender/tool/util');
  71. var zrColor = require('zrender/tool/color');
  72. var zrArea = require('zrender/tool/area');
  73. /**
  74. * 构造函数
  75. * @param {Object} messageCenter echart消息中心
  76. * @param {ZRender} zr zrender实例
  77. * @param {Object} series 数据
  78. * @param {Object} component 组件
  79. */
  80. function Funnel(ecTheme, messageCenter, zr, option, myChart) {
  81. // 图表基类
  82. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  83. this.refresh(option);
  84. }
  85. Funnel.prototype = {
  86. type: ecConfig.CHART_TYPE_FUNNEL,
  87. /**
  88. * 绘制图形
  89. */
  90. _buildShape: function () {
  91. var series = this.series;
  92. var legend = this.component.legend;
  93. // 复用参数索引
  94. this._paramsMap = {};
  95. this._selected = {};
  96. this.selectedMap = {};
  97. var serieName;
  98. for (var i = 0, l = series.length; i < l; i++) {
  99. if (series[i].type === ecConfig.CHART_TYPE_FUNNEL) {
  100. series[i] = this.reformOption(series[i]);
  101. this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;
  102. serieName = series[i].name || '';
  103. // 系列图例开关
  104. this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;
  105. if (!this.selectedMap[serieName]) {
  106. continue;
  107. }
  108. this._buildSingleFunnel(i);
  109. this.buildMark(i);
  110. }
  111. }
  112. this.addShapeList();
  113. },
  114. /**
  115. * 构建单个仪表盘
  116. *
  117. * @param {number} seriesIndex 系列索引
  118. */
  119. _buildSingleFunnel: function (seriesIndex) {
  120. var legend = this.component.legend;
  121. var serie = this.series[seriesIndex];
  122. var data = this._mapData(seriesIndex);
  123. var location = this._getLocation(seriesIndex);
  124. this._paramsMap[seriesIndex] = {
  125. location: location,
  126. data: data
  127. };
  128. var itemName;
  129. var total = 0;
  130. var selectedData = [];
  131. // 计算需要显示的个数和总值
  132. for (var i = 0, l = data.length; i < l; i++) {
  133. itemName = data[i].name;
  134. this.selectedMap[itemName] = legend ? legend.isSelected(itemName) : true;
  135. if (this.selectedMap[itemName] && !isNaN(data[i].value)) {
  136. selectedData.push(data[i]);
  137. total++;
  138. }
  139. }
  140. if (total === 0) {
  141. return;
  142. }
  143. // 可计算箱子
  144. var funnelCase = this._buildFunnelCase(seriesIndex);
  145. var align = serie.funnelAlign;
  146. var gap = serie.gap;
  147. var height = total > 1
  148. ? (location.height - (total - 1) * gap) / total : location.height;
  149. var width;
  150. var lastY = location.y;
  151. var lastWidth = serie.sort === 'descending'
  152. ? this._getItemWidth(seriesIndex, selectedData[0].value)
  153. : number.parsePercent(serie.minSize, location.width);
  154. var next = serie.sort === 'descending' ? 1 : 0;
  155. var centerX = location.centerX;
  156. var pointList= [];
  157. var x;
  158. var polygon;
  159. var lastPolygon;
  160. for (var i = 0, l = selectedData.length; i < l; i++) {
  161. itemName = selectedData[i].name;
  162. if (this.selectedMap[itemName] && !isNaN(selectedData[i].value)) {
  163. width = i <= l - 2
  164. ? this._getItemWidth(seriesIndex, selectedData[i + next].value)
  165. : serie.sort === 'descending'
  166. ? number.parsePercent(serie.minSize, location.width)
  167. : number.parsePercent(serie.maxSize, location.width);
  168. switch (align) {
  169. case 'left':
  170. x = location.x;
  171. break;
  172. case 'right':
  173. x = location.x + location.width - lastWidth;
  174. break;
  175. default:
  176. x = centerX - lastWidth / 2;
  177. }
  178. polygon = this._buildItem(
  179. seriesIndex, selectedData[i]._index,
  180. legend // color
  181. ? legend.getColor(itemName)
  182. : this.zr.getColor(selectedData[i]._index),
  183. x, lastY, lastWidth, width, height, align
  184. );
  185. lastY += height + gap;
  186. lastPolygon = polygon.style.pointList;
  187. pointList.unshift([lastPolygon[0][0] - 10, lastPolygon[0][1]]); // 左
  188. pointList.push([lastPolygon[1][0] + 10, lastPolygon[1][1]]); // 右
  189. if (i === 0) {
  190. if (lastWidth === 0) {
  191. lastPolygon = pointList.pop();
  192. align == 'center' && (pointList[0][0] += 10);
  193. align == 'right' && (pointList[0][0] = lastPolygon[0]);
  194. pointList[0][1] -= align == 'center' ? 10 : 15;
  195. if (l == 1) {
  196. lastPolygon = polygon.style.pointList;
  197. }
  198. }
  199. else {
  200. pointList[pointList.length - 1][1] -= 5;
  201. pointList[0][1] -=5;
  202. }
  203. }
  204. lastWidth = width;
  205. }
  206. }
  207. if (funnelCase) {
  208. pointList.unshift([lastPolygon[3][0] - 10, lastPolygon[3][1]]); // 左
  209. pointList.push([lastPolygon[2][0] + 10, lastPolygon[2][1]]); // 右
  210. if (lastWidth === 0) {
  211. lastPolygon = pointList.pop();
  212. align == 'center' && (pointList[0][0] += 10);
  213. align == 'right' && (pointList[0][0] = lastPolygon[0]);
  214. pointList[0][1] += align == 'center' ? 10 : 15;
  215. }
  216. else {
  217. pointList[pointList.length - 1][1] += 5;
  218. pointList[0][1] +=5;
  219. }
  220. funnelCase.style.pointList = pointList;
  221. }
  222. },
  223. _buildFunnelCase: function(seriesIndex) {
  224. var serie = this.series[seriesIndex];
  225. if (this.deepQuery([serie, this.option], 'calculable')) {
  226. var location = this._paramsMap[seriesIndex].location;
  227. var gap = 10;
  228. var funnelCase = {
  229. hoverable: false,
  230. style: {
  231. pointListd: [
  232. [location.x - gap, location.y - gap],
  233. [location.x + location.width + gap, location.y - gap],
  234. [location.x + location.width + gap, location.y + location.height + gap],
  235. [location.x - gap, location.y + location.height + gap]
  236. ],
  237. brushType: 'stroke',
  238. lineWidth: 1,
  239. strokeColor: serie.calculableHolderColor
  240. || this.ecTheme.calculableHolderColor
  241. || ecConfig.calculableHolderColor
  242. }
  243. };
  244. ecData.pack(funnelCase, serie, seriesIndex, undefined, -1);
  245. this.setCalculable(funnelCase);
  246. funnelCase = new PolygonShape(funnelCase);
  247. this.shapeList.push(funnelCase);
  248. return funnelCase;
  249. }
  250. },
  251. _getLocation: function (seriesIndex) {
  252. var gridOption = this.series[seriesIndex];
  253. var zrWidth = this.zr.getWidth();
  254. var zrHeight = this.zr.getHeight();
  255. var x = this.parsePercent(gridOption.x, zrWidth);
  256. var y = this.parsePercent(gridOption.y, zrHeight);
  257. var width = gridOption.width == null
  258. ? (zrWidth - x - this.parsePercent(gridOption.x2, zrWidth))
  259. : this.parsePercent(gridOption.width, zrWidth);
  260. return {
  261. x: x,
  262. y: y,
  263. width: width,
  264. height: gridOption.height == null
  265. ? (zrHeight - y - this.parsePercent(gridOption.y2, zrHeight))
  266. : this.parsePercent(gridOption.height, zrHeight),
  267. centerX: x + width / 2
  268. };
  269. },
  270. _mapData: function(seriesIndex) {
  271. var serie = this.series[seriesIndex];
  272. var funnelData = zrUtil.clone(serie.data);
  273. for (var i = 0, l = funnelData.length; i < l; i++) {
  274. funnelData[i]._index = i;
  275. }
  276. function numDescending (a, b) {
  277. if (a.value === '-') {
  278. return 1;
  279. }
  280. else if (b.value === '-') {
  281. return -1;
  282. }
  283. return b.value - a.value;
  284. }
  285. function numAscending (a, b) {
  286. return -numDescending(a, b);
  287. }
  288. if (serie.sort != 'none') {
  289. funnelData.sort(serie.sort === 'descending' ? numDescending : numAscending);
  290. }
  291. return funnelData;
  292. },
  293. /**
  294. * 构建单个扇形及指标
  295. */
  296. _buildItem: function (
  297. seriesIndex, dataIndex, defaultColor,
  298. x, y, topWidth, bottomWidth, height, align
  299. ) {
  300. var series = this.series;
  301. var serie = series[seriesIndex];
  302. var data = serie.data[dataIndex];
  303. // 漏斗
  304. var polygon = this.getPolygon(
  305. seriesIndex, dataIndex, defaultColor,
  306. x, y, topWidth, bottomWidth, height, align
  307. );
  308. ecData.pack(
  309. polygon,
  310. series[seriesIndex], seriesIndex,
  311. series[seriesIndex].data[dataIndex], dataIndex,
  312. series[seriesIndex].data[dataIndex].name
  313. );
  314. this.shapeList.push(polygon);
  315. // 文本标签
  316. var label = this.getLabel(
  317. seriesIndex, dataIndex, defaultColor,
  318. x, y, topWidth, bottomWidth, height, align
  319. );
  320. ecData.pack(
  321. label,
  322. series[seriesIndex], seriesIndex,
  323. series[seriesIndex].data[dataIndex], dataIndex,
  324. series[seriesIndex].data[dataIndex].name
  325. );
  326. this.shapeList.push(label);
  327. // 特定状态下是否需要显示文本标签
  328. if (!this._needLabel(serie, data,false)) {
  329. label.invisible = true;
  330. }
  331. // 文本标签视觉引导线
  332. var labelLine = this.getLabelLine(
  333. seriesIndex, dataIndex, defaultColor,
  334. x, y, topWidth, bottomWidth, height, align
  335. );
  336. this.shapeList.push(labelLine);
  337. // 特定状态下是否需要显示文本标签引导线
  338. if (!this._needLabelLine(serie, data,false)) {
  339. labelLine.invisible = true;
  340. }
  341. var polygonHoverConnect = [];
  342. var labelHoverConnect = [];
  343. if (this._needLabelLine(serie, data, true)) {
  344. polygonHoverConnect.push(labelLine.id);
  345. labelHoverConnect.push(labelLine.id);
  346. }
  347. if (this._needLabel(serie, data, true)) {
  348. polygonHoverConnect.push(label.id);
  349. labelHoverConnect.push(polygon.id);
  350. }
  351. polygon.hoverConnect = polygonHoverConnect;
  352. label.hoverConnect = labelHoverConnect;
  353. return polygon;
  354. },
  355. /**
  356. * 根据值计算宽度
  357. */
  358. _getItemWidth: function (seriesIndex, value) {
  359. var serie = this.series[seriesIndex];
  360. var location = this._paramsMap[seriesIndex].location;
  361. var min = serie.min;
  362. var max = serie.max;
  363. var minSize = number.parsePercent(serie.minSize, location.width);
  364. var maxSize = number.parsePercent(serie.maxSize, location.width);
  365. return (value - min) * (maxSize - minSize) / (max - min) + minSize;
  366. },
  367. /**
  368. * 构建扇形
  369. */
  370. getPolygon: function (
  371. seriesIndex, dataIndex, defaultColor,
  372. xLT, y, topWidth, bottomWidth, height, align
  373. ) {
  374. var serie = this.series[seriesIndex];
  375. var data = serie.data[dataIndex];
  376. var queryTarget = [data, serie];
  377. // 多级控制
  378. var normal = this.deepMerge(queryTarget, 'itemStyle.normal') || {};
  379. var emphasis = this.deepMerge(queryTarget,'itemStyle.emphasis') || {};
  380. var normalColor = this.getItemStyleColor(normal.color, seriesIndex, dataIndex, data)
  381. || defaultColor;
  382. var emphasisColor = this.getItemStyleColor(emphasis.color, seriesIndex, dataIndex, data)
  383. || (typeof normalColor === 'string'
  384. ? zrColor.lift(normalColor, -0.2)
  385. : normalColor
  386. );
  387. var xLB;
  388. switch (align) {
  389. case 'left':
  390. xLB = xLT;
  391. break;
  392. case 'right':
  393. xLB = xLT + (topWidth - bottomWidth);
  394. break;
  395. default:
  396. xLB = xLT + (topWidth - bottomWidth) / 2;
  397. break;
  398. }
  399. var polygon = {
  400. zlevel: serie.zlevel,
  401. z: serie.z,
  402. clickable: this.deepQuery(queryTarget, 'clickable'),
  403. style: {
  404. pointList: [
  405. [xLT, y],
  406. [xLT + topWidth, y],
  407. [xLB + bottomWidth, y + height],
  408. [xLB, y + height]
  409. ],
  410. brushType: 'both',
  411. color: normalColor,
  412. lineWidth: normal.borderWidth,
  413. strokeColor: normal.borderColor
  414. },
  415. highlightStyle: {
  416. color: emphasisColor,
  417. lineWidth: emphasis.borderWidth,
  418. strokeColor: emphasis.borderColor
  419. }
  420. };
  421. if (this.deepQuery([data, serie, this.option], 'calculable')) {
  422. this.setCalculable(polygon);
  423. polygon.draggable = true;
  424. }
  425. return new PolygonShape(polygon);
  426. },
  427. /**
  428. * 需要显示则会有返回构建好的shape,否则返回undefined
  429. */
  430. getLabel: function (
  431. seriesIndex, dataIndex, defaultColor,
  432. x, y, topWidth, bottomWidth, height, align
  433. ) {
  434. var serie = this.series[seriesIndex];
  435. var data = serie.data[dataIndex];
  436. var location = this._paramsMap[seriesIndex].location;
  437. // serie里有默认配置,放心大胆的用!
  438. var itemStyle = zrUtil.merge(
  439. zrUtil.clone(data.itemStyle) || {},
  440. serie.itemStyle
  441. );
  442. var status = 'normal';
  443. // label配置
  444. var labelControl = itemStyle[status].label;
  445. var textStyle = labelControl.textStyle || {};
  446. var lineLength = itemStyle[status].labelLine.length;
  447. var text = this.getLabelText(seriesIndex, dataIndex, status);
  448. var textFont = this.getFont(textStyle);
  449. var textAlign;
  450. var textColor = defaultColor;
  451. labelControl.position = labelControl.position
  452. || itemStyle.normal.label.position;
  453. if (labelControl.position === 'inner'
  454. || labelControl.position === 'inside'
  455. || labelControl.position === 'center'
  456. ) {
  457. // 内部
  458. textAlign = align;
  459. textColor =
  460. Math.max(topWidth, bottomWidth) / 2 > zrArea.getTextWidth(text, textFont)
  461. ? '#fff' : zrColor.reverse(defaultColor);
  462. }
  463. else if (labelControl.position === 'left'){
  464. // 左侧显示
  465. textAlign = 'right';
  466. }
  467. else {
  468. // 右侧显示,默认 labelControl.position === 'outer' || 'right)
  469. textAlign = 'left';
  470. }
  471. var textShape = {
  472. zlevel: serie.zlevel,
  473. z: serie.z + 1,
  474. style: {
  475. x: this._getLabelPoint(
  476. labelControl.position, x, location,
  477. topWidth, bottomWidth,lineLength, align
  478. ),
  479. y: y + height / 2,
  480. color: textStyle.color || textColor,
  481. text: text,
  482. textAlign: textStyle.align || textAlign,
  483. textBaseline: textStyle.baseline || 'middle',
  484. textFont: textFont
  485. }
  486. };
  487. //----------高亮
  488. status = 'emphasis';
  489. // label配置
  490. labelControl = itemStyle[status].label || labelControl;
  491. textStyle = labelControl.textStyle || textStyle;
  492. lineLength = itemStyle[status].labelLine.length || lineLength;
  493. labelControl.position = labelControl.position || itemStyle.normal.label.position;
  494. text = this.getLabelText(seriesIndex, dataIndex, status);
  495. textFont = this.getFont(textStyle);
  496. textColor = defaultColor;
  497. if (labelControl.position === 'inner'
  498. || labelControl.position === 'inside'
  499. || labelControl.position === 'center'
  500. ) {
  501. // 内部
  502. textAlign = align;
  503. textColor =
  504. Math.max(topWidth, bottomWidth) / 2 > zrArea.getTextWidth(text, textFont)
  505. ? '#fff' : zrColor.reverse(defaultColor);
  506. }
  507. else if (labelControl.position === 'left'){
  508. // 左侧显示
  509. textAlign = 'right';
  510. }
  511. else {
  512. // 右侧显示,默认 labelControl.position === 'outer' || 'right)
  513. textAlign = 'left';
  514. }
  515. textShape.highlightStyle = {
  516. x: this._getLabelPoint(
  517. labelControl.position, x, location,
  518. topWidth, bottomWidth,lineLength, align
  519. ),
  520. color: textStyle.color || textColor,
  521. text: text,
  522. textAlign: textStyle.align || textAlign,
  523. textFont: textFont,
  524. brushType: 'fill'
  525. };
  526. return new TextShape(textShape);
  527. },
  528. /**
  529. * 根据lable.format计算label text
  530. */
  531. getLabelText: function (seriesIndex, dataIndex, status) {
  532. var series = this.series;
  533. var serie = series[seriesIndex];
  534. var data = serie.data[dataIndex];
  535. var formatter = this.deepQuery(
  536. [data, serie],
  537. 'itemStyle.' + status + '.label.formatter'
  538. );
  539. if (formatter) {
  540. if (typeof formatter === 'function') {
  541. return formatter.call(
  542. this.myChart,
  543. {
  544. seriesIndex: seriesIndex,
  545. seriesName: serie.name || '',
  546. series: serie,
  547. dataIndex: dataIndex,
  548. data: data,
  549. name: data.name,
  550. value: data.value
  551. }
  552. );
  553. }
  554. else if (typeof formatter === 'string') {
  555. formatter = formatter.replace('{a}','{a0}')
  556. .replace('{b}','{b0}')
  557. .replace('{c}','{c0}')
  558. .replace('{a0}', serie.name)
  559. .replace('{b0}', data.name)
  560. .replace('{c0}', data.value);
  561. return formatter;
  562. }
  563. }
  564. else {
  565. return data.name;
  566. }
  567. },
  568. /**
  569. * 需要显示则会有返回构建好的shape,否则返回undefined
  570. */
  571. getLabelLine: function (
  572. seriesIndex, dataIndex, defaultColor,
  573. x, y, topWidth, bottomWidth, height, align
  574. ) {
  575. var serie = this.series[seriesIndex];
  576. var data = serie.data[dataIndex];
  577. var location = this._paramsMap[seriesIndex].location;
  578. // serie里有默认配置,放心大胆的用!
  579. var itemStyle = zrUtil.merge(
  580. zrUtil.clone(data.itemStyle) || {},
  581. serie.itemStyle
  582. );
  583. var status = 'normal';
  584. // labelLine配置
  585. var labelLineControl = itemStyle[status].labelLine;
  586. var lineLength = itemStyle[status].labelLine.length;
  587. var lineStyle = labelLineControl.lineStyle || {};
  588. var labelControl = itemStyle[status].label;
  589. labelControl.position = labelControl.position
  590. || itemStyle.normal.label.position;
  591. var lineShape = {
  592. zlevel: serie.zlevel,
  593. z: serie.z + 1,
  594. hoverable: false,
  595. style: {
  596. xStart: this._getLabelLineStartPoint(x, location, topWidth, bottomWidth, align),
  597. yStart: y + height / 2,
  598. xEnd: this._getLabelPoint(
  599. labelControl.position, x, location,
  600. topWidth, bottomWidth,lineLength, align
  601. ),
  602. yEnd: y + height / 2,
  603. strokeColor: lineStyle.color || defaultColor,
  604. lineType: lineStyle.type,
  605. lineWidth: lineStyle.width
  606. }
  607. };
  608. status = 'emphasis';
  609. // labelLine配置
  610. labelLineControl = itemStyle[status].labelLine || labelLineControl;
  611. lineLength = itemStyle[status].labelLine.length || lineLength;
  612. lineStyle = labelLineControl.lineStyle || lineStyle;
  613. labelControl = itemStyle[status].label || labelControl;
  614. labelControl.position = labelControl.position;
  615. lineShape.highlightStyle = {
  616. xEnd: this._getLabelPoint(
  617. labelControl.position, x, location,
  618. topWidth, bottomWidth,lineLength, align
  619. ),
  620. strokeColor: lineStyle.color || defaultColor,
  621. lineType: lineStyle.type,
  622. lineWidth: lineStyle.width
  623. };
  624. return new LineShape(lineShape);
  625. },
  626. _getLabelPoint: function(position, x, location, topWidth, bottomWidth, lineLength, align) {
  627. position = (position === 'inner' || position === 'inside') ? 'center' : position;
  628. switch (position) {
  629. case 'center':
  630. return align == 'center'
  631. ? (x + topWidth / 2)
  632. : align == 'left' ? (x + 10) : (x + topWidth - 10);
  633. case 'left':
  634. // 左侧文本
  635. if (lineLength === 'auto') {
  636. return location.x - 10;
  637. }
  638. else {
  639. return align == 'center'
  640. // 居中布局
  641. ? (location.centerX - Math.max(topWidth, bottomWidth) / 2 - lineLength)
  642. : align == 'right'
  643. // 右对齐布局
  644. ? (x
  645. - (topWidth < bottomWidth ? (bottomWidth - topWidth) : 0)
  646. - lineLength
  647. )
  648. // 左对齐布局
  649. : (location.x - lineLength);
  650. }
  651. break;
  652. default:
  653. // 右侧文本
  654. if (lineLength === 'auto') {
  655. return location.x + location.width + 10;
  656. }
  657. else {
  658. return align == 'center'
  659. // 居中布局
  660. ? (location.centerX + Math.max(topWidth, bottomWidth) / 2 + lineLength)
  661. : align == 'right'
  662. // 右对齐布局
  663. ? (location.x + location.width + lineLength)
  664. // 左对齐布局
  665. : (x + Math.max(topWidth, bottomWidth) + lineLength);
  666. }
  667. }
  668. },
  669. _getLabelLineStartPoint: function(x, location, topWidth, bottomWidth, align) {
  670. return align == 'center'
  671. ? location.centerX
  672. : topWidth < bottomWidth
  673. ? (x + Math.min(topWidth, bottomWidth) / 2)
  674. : (x + Math.max(topWidth, bottomWidth) / 2);
  675. },
  676. /**
  677. * 返回特定状态(normal or emphasis)下是否需要显示label标签文本
  678. * @param {Object} serie
  679. * @param {Object} data
  680. * @param {boolean} isEmphasis true is 'emphasis' and false is 'normal'
  681. */
  682. _needLabel: function (serie, data, isEmphasis) {
  683. return this.deepQuery(
  684. [data, serie],
  685. 'itemStyle.'
  686. + (isEmphasis ? 'emphasis' : 'normal')
  687. + '.label.show'
  688. );
  689. },
  690. /**
  691. * 返回特定状态(normal or emphasis)下是否需要显示labelLine标签视觉引导线
  692. * @param {Object} serie
  693. * @param {Object} data
  694. * @param {boolean} isEmphasis true is 'emphasis' and false is 'normal'
  695. */
  696. _needLabelLine: function (serie, data, isEmphasis) {
  697. return this.deepQuery(
  698. [data, serie],
  699. 'itemStyle.'
  700. + (isEmphasis ? 'emphasis' : 'normal')
  701. +'.labelLine.show'
  702. );
  703. },
  704. /**
  705. * 刷新
  706. */
  707. refresh: function (newOption) {
  708. if (newOption) {
  709. this.option = newOption;
  710. this.series = newOption.series;
  711. }
  712. this.backupShapeList();
  713. this._buildShape();
  714. }
  715. };
  716. zrUtil.inherits(Funnel, ChartBase);
  717. // 图表注册
  718. require('../chart').define('funnel', Funnel);
  719. return Funnel;
  720. });