gauge.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. define('echarts/chart/gauge', [
  2. 'require',
  3. './base',
  4. '../util/shape/GaugePointer',
  5. 'zrender/shape/Text',
  6. 'zrender/shape/Line',
  7. 'zrender/shape/Rectangle',
  8. 'zrender/shape/Circle',
  9. 'zrender/shape/Sector',
  10. '../config',
  11. '../util/ecData',
  12. '../util/accMath',
  13. 'zrender/tool/util',
  14. '../chart'
  15. ], function (require) {
  16. var ChartBase = require('./base');
  17. var GaugePointerShape = require('../util/shape/GaugePointer');
  18. var TextShape = require('zrender/shape/Text');
  19. var LineShape = require('zrender/shape/Line');
  20. var RectangleShape = require('zrender/shape/Rectangle');
  21. var CircleShape = require('zrender/shape/Circle');
  22. var SectorShape = require('zrender/shape/Sector');
  23. var ecConfig = require('../config');
  24. ecConfig.gauge = {
  25. zlevel: 0,
  26. z: 2,
  27. center: [
  28. '50%',
  29. '50%'
  30. ],
  31. clickable: true,
  32. legendHoverLink: true,
  33. radius: '75%',
  34. startAngle: 225,
  35. endAngle: -45,
  36. min: 0,
  37. max: 100,
  38. splitNumber: 10,
  39. axisLine: {
  40. show: true,
  41. lineStyle: {
  42. color: [
  43. [
  44. 0.2,
  45. '#228b22'
  46. ],
  47. [
  48. 0.8,
  49. '#48b'
  50. ],
  51. [
  52. 1,
  53. '#ff4500'
  54. ]
  55. ],
  56. width: 30
  57. }
  58. },
  59. axisTick: {
  60. show: true,
  61. splitNumber: 5,
  62. length: 8,
  63. lineStyle: {
  64. color: '#eee',
  65. width: 1,
  66. type: 'solid'
  67. }
  68. },
  69. axisLabel: {
  70. show: true,
  71. textStyle: { color: 'auto' }
  72. },
  73. splitLine: {
  74. show: true,
  75. length: 30,
  76. lineStyle: {
  77. color: '#eee',
  78. width: 2,
  79. type: 'solid'
  80. }
  81. },
  82. pointer: {
  83. show: true,
  84. length: '80%',
  85. width: 8,
  86. color: 'auto'
  87. },
  88. title: {
  89. show: true,
  90. offsetCenter: [
  91. 0,
  92. '-40%'
  93. ],
  94. textStyle: {
  95. color: '#333',
  96. fontSize: 15
  97. }
  98. },
  99. detail: {
  100. show: true,
  101. backgroundColor: 'rgba(0,0,0,0)',
  102. borderWidth: 0,
  103. borderColor: '#ccc',
  104. width: 100,
  105. height: 40,
  106. offsetCenter: [
  107. 0,
  108. '40%'
  109. ],
  110. textStyle: {
  111. color: 'auto',
  112. fontSize: 30
  113. }
  114. }
  115. };
  116. var ecData = require('../util/ecData');
  117. var accMath = require('../util/accMath');
  118. var zrUtil = require('zrender/tool/util');
  119. function Gauge(ecTheme, messageCenter, zr, option, myChart) {
  120. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  121. this.refresh(option);
  122. }
  123. Gauge.prototype = {
  124. type: ecConfig.CHART_TYPE_GAUGE,
  125. _buildShape: function () {
  126. var series = this.series;
  127. this._paramsMap = {};
  128. for (var i = 0, l = series.length; i < l; i++) {
  129. if (series[i].type === ecConfig.CHART_TYPE_GAUGE) {
  130. series[i] = this.reformOption(series[i]);
  131. this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;
  132. this._buildSingleGauge(i);
  133. this.buildMark(i);
  134. }
  135. }
  136. this.addShapeList();
  137. },
  138. _buildSingleGauge: function (seriesIndex) {
  139. var serie = this.series[seriesIndex];
  140. this._paramsMap[seriesIndex] = {
  141. center: this.parseCenter(this.zr, serie.center),
  142. radius: this.parseRadius(this.zr, serie.radius),
  143. startAngle: serie.startAngle.toFixed(2) - 0,
  144. endAngle: serie.endAngle.toFixed(2) - 0
  145. };
  146. this._paramsMap[seriesIndex].totalAngle = this._paramsMap[seriesIndex].startAngle - this._paramsMap[seriesIndex].endAngle;
  147. this._colorMap(seriesIndex);
  148. this._buildAxisLine(seriesIndex);
  149. this._buildSplitLine(seriesIndex);
  150. this._buildAxisTick(seriesIndex);
  151. this._buildAxisLabel(seriesIndex);
  152. this._buildPointer(seriesIndex);
  153. this._buildTitle(seriesIndex);
  154. this._buildDetail(seriesIndex);
  155. },
  156. _buildAxisLine: function (seriesIndex) {
  157. var serie = this.series[seriesIndex];
  158. if (!serie.axisLine.show) {
  159. return;
  160. }
  161. var min = serie.min;
  162. var total = serie.max - min;
  163. var params = this._paramsMap[seriesIndex];
  164. var center = params.center;
  165. var startAngle = params.startAngle;
  166. var totalAngle = params.totalAngle;
  167. var colorArray = params.colorArray;
  168. var lineStyle = serie.axisLine.lineStyle;
  169. var lineWidth = this.parsePercent(lineStyle.width, params.radius[1]);
  170. var r = params.radius[1];
  171. var r0 = r - lineWidth;
  172. var sectorShape;
  173. var lastAngle = startAngle;
  174. var newAngle;
  175. for (var i = 0, l = colorArray.length; i < l; i++) {
  176. newAngle = startAngle - totalAngle * (colorArray[i][0] - min) / total;
  177. sectorShape = this._getSector(center, r0, r, newAngle, lastAngle, colorArray[i][1], lineStyle);
  178. lastAngle = newAngle;
  179. sectorShape._animationAdd = 'r';
  180. ecData.set(sectorShape, 'seriesIndex', seriesIndex);
  181. ecData.set(sectorShape, 'dataIndex', i);
  182. this.shapeList.push(sectorShape);
  183. }
  184. },
  185. _buildSplitLine: function (seriesIndex) {
  186. var serie = this.series[seriesIndex];
  187. if (!serie.splitLine.show) {
  188. return;
  189. }
  190. var params = this._paramsMap[seriesIndex];
  191. var splitNumber = serie.splitNumber;
  192. var min = serie.min;
  193. var total = serie.max - min;
  194. var splitLine = serie.splitLine;
  195. var length = this.parsePercent(splitLine.length, params.radius[1]);
  196. var lineStyle = splitLine.lineStyle;
  197. var color = lineStyle.color;
  198. var center = params.center;
  199. var startAngle = params.startAngle * Math.PI / 180;
  200. var totalAngle = params.totalAngle * Math.PI / 180;
  201. var r = params.radius[1];
  202. var r0 = r - length;
  203. var angle;
  204. var sinAngle;
  205. var cosAngle;
  206. for (var i = 0; i <= splitNumber; i++) {
  207. angle = startAngle - totalAngle / splitNumber * i;
  208. sinAngle = Math.sin(angle);
  209. cosAngle = Math.cos(angle);
  210. this.shapeList.push(new LineShape({
  211. zlevel: this.getZlevelBase(),
  212. z: this.getZBase() + 1,
  213. hoverable: false,
  214. style: {
  215. xStart: center[0] + cosAngle * r,
  216. yStart: center[1] - sinAngle * r,
  217. xEnd: center[0] + cosAngle * r0,
  218. yEnd: center[1] - sinAngle * r0,
  219. strokeColor: color === 'auto' ? this._getColor(seriesIndex, min + total / splitNumber * i) : color,
  220. lineType: lineStyle.type,
  221. lineWidth: lineStyle.width,
  222. shadowColor: lineStyle.shadowColor,
  223. shadowBlur: lineStyle.shadowBlur,
  224. shadowOffsetX: lineStyle.shadowOffsetX,
  225. shadowOffsetY: lineStyle.shadowOffsetY
  226. }
  227. }));
  228. }
  229. },
  230. _buildAxisTick: function (seriesIndex) {
  231. var serie = this.series[seriesIndex];
  232. if (!serie.axisTick.show) {
  233. return;
  234. }
  235. var params = this._paramsMap[seriesIndex];
  236. var splitNumber = serie.splitNumber;
  237. var min = serie.min;
  238. var total = serie.max - min;
  239. var axisTick = serie.axisTick;
  240. var tickSplit = axisTick.splitNumber;
  241. var length = this.parsePercent(axisTick.length, params.radius[1]);
  242. var lineStyle = axisTick.lineStyle;
  243. var color = lineStyle.color;
  244. var center = params.center;
  245. var startAngle = params.startAngle * Math.PI / 180;
  246. var totalAngle = params.totalAngle * Math.PI / 180;
  247. var r = params.radius[1];
  248. var r0 = r - length;
  249. var angle;
  250. var sinAngle;
  251. var cosAngle;
  252. for (var i = 0, l = splitNumber * tickSplit; i <= l; i++) {
  253. if (i % tickSplit === 0) {
  254. continue;
  255. }
  256. angle = startAngle - totalAngle / l * i;
  257. sinAngle = Math.sin(angle);
  258. cosAngle = Math.cos(angle);
  259. this.shapeList.push(new LineShape({
  260. zlevel: this.getZlevelBase(),
  261. z: this.getZBase() + 1,
  262. hoverable: false,
  263. style: {
  264. xStart: center[0] + cosAngle * r,
  265. yStart: center[1] - sinAngle * r,
  266. xEnd: center[0] + cosAngle * r0,
  267. yEnd: center[1] - sinAngle * r0,
  268. strokeColor: color === 'auto' ? this._getColor(seriesIndex, min + total / l * i) : color,
  269. lineType: lineStyle.type,
  270. lineWidth: lineStyle.width,
  271. shadowColor: lineStyle.shadowColor,
  272. shadowBlur: lineStyle.shadowBlur,
  273. shadowOffsetX: lineStyle.shadowOffsetX,
  274. shadowOffsetY: lineStyle.shadowOffsetY
  275. }
  276. }));
  277. }
  278. },
  279. _buildAxisLabel: function (seriesIndex) {
  280. var serie = this.series[seriesIndex];
  281. if (!serie.axisLabel.show) {
  282. return;
  283. }
  284. var splitNumber = serie.splitNumber;
  285. var min = serie.min;
  286. var total = serie.max - min;
  287. var textStyle = serie.axisLabel.textStyle;
  288. var textFont = this.getFont(textStyle);
  289. var color = textStyle.color;
  290. var params = this._paramsMap[seriesIndex];
  291. var center = params.center;
  292. var startAngle = params.startAngle;
  293. var totalAngle = params.totalAngle;
  294. var r0 = params.radius[1] - this.parsePercent(serie.splitLine.length, params.radius[1]) - 5;
  295. var angle;
  296. var sinAngle;
  297. var cosAngle;
  298. var value;
  299. for (var i = 0; i <= splitNumber; i++) {
  300. value = accMath.accAdd(min, accMath.accMul(accMath.accDiv(total, splitNumber), i));
  301. angle = startAngle - totalAngle / splitNumber * i;
  302. sinAngle = Math.sin(angle * Math.PI / 180);
  303. cosAngle = Math.cos(angle * Math.PI / 180);
  304. angle = (angle + 360) % 360;
  305. this.shapeList.push(new TextShape({
  306. zlevel: this.getZlevelBase(),
  307. z: this.getZBase() + 1,
  308. hoverable: false,
  309. style: {
  310. x: center[0] + cosAngle * r0,
  311. y: center[1] - sinAngle * r0,
  312. color: color === 'auto' ? this._getColor(seriesIndex, value) : color,
  313. text: this._getLabelText(serie.axisLabel.formatter, value),
  314. textAlign: angle >= 110 && angle <= 250 ? 'left' : angle <= 70 || angle >= 290 ? 'right' : 'center',
  315. textBaseline: angle >= 10 && angle <= 170 ? 'top' : angle >= 190 && angle <= 350 ? 'bottom' : 'middle',
  316. textFont: textFont,
  317. shadowColor: textStyle.shadowColor,
  318. shadowBlur: textStyle.shadowBlur,
  319. shadowOffsetX: textStyle.shadowOffsetX,
  320. shadowOffsetY: textStyle.shadowOffsetY
  321. }
  322. }));
  323. }
  324. },
  325. _buildPointer: function (seriesIndex) {
  326. var serie = this.series[seriesIndex];
  327. if (!serie.pointer.show) {
  328. return;
  329. }
  330. var total = serie.max - serie.min;
  331. var pointer = serie.pointer;
  332. var params = this._paramsMap[seriesIndex];
  333. var length = this.parsePercent(pointer.length, params.radius[1]);
  334. var width = this.parsePercent(pointer.width, params.radius[1]);
  335. var center = params.center;
  336. var value = this._getValue(seriesIndex);
  337. value = value < serie.max ? value : serie.max;
  338. var angle = (params.startAngle - params.totalAngle / total * (value - serie.min)) * Math.PI / 180;
  339. var color = pointer.color === 'auto' ? this._getColor(seriesIndex, value) : pointer.color;
  340. var pointShape = new GaugePointerShape({
  341. zlevel: this.getZlevelBase(),
  342. z: this.getZBase() + 1,
  343. clickable: this.query(serie, 'clickable'),
  344. style: {
  345. x: center[0],
  346. y: center[1],
  347. r: length,
  348. startAngle: params.startAngle * Math.PI / 180,
  349. angle: angle,
  350. color: color,
  351. width: width,
  352. shadowColor: pointer.shadowColor,
  353. shadowBlur: pointer.shadowBlur,
  354. shadowOffsetX: pointer.shadowOffsetX,
  355. shadowOffsetY: pointer.shadowOffsetY
  356. },
  357. highlightStyle: {
  358. brushType: 'fill',
  359. width: width > 2 ? 2 : width / 2,
  360. color: '#fff'
  361. }
  362. });
  363. ecData.pack(pointShape, this.series[seriesIndex], seriesIndex, this.series[seriesIndex].data[0], 0, this.series[seriesIndex].data[0].name, value);
  364. this.shapeList.push(pointShape);
  365. this.shapeList.push(new CircleShape({
  366. zlevel: this.getZlevelBase(),
  367. z: this.getZBase() + 2,
  368. hoverable: false,
  369. style: {
  370. x: center[0],
  371. y: center[1],
  372. r: pointer.width / 2.5,
  373. color: '#fff'
  374. }
  375. }));
  376. },
  377. _buildTitle: function (seriesIndex) {
  378. var serie = this.series[seriesIndex];
  379. if (!serie.title.show) {
  380. return;
  381. }
  382. var data = serie.data[0];
  383. var name = data.name != null ? data.name : '';
  384. if (name !== '') {
  385. var title = serie.title;
  386. var offsetCenter = title.offsetCenter;
  387. var textStyle = title.textStyle;
  388. var textColor = textStyle.color;
  389. var params = this._paramsMap[seriesIndex];
  390. var x = params.center[0] + this.parsePercent(offsetCenter[0], params.radius[1]);
  391. var y = params.center[1] + this.parsePercent(offsetCenter[1], params.radius[1]);
  392. this.shapeList.push(new TextShape({
  393. zlevel: this.getZlevelBase(),
  394. z: this.getZBase() + (Math.abs(x - params.center[0]) + Math.abs(y - params.center[1]) < textStyle.fontSize * 2 ? 2 : 1),
  395. hoverable: false,
  396. style: {
  397. x: x,
  398. y: y,
  399. color: textColor === 'auto' ? this._getColor(seriesIndex) : textColor,
  400. text: name,
  401. textAlign: 'center',
  402. textFont: this.getFont(textStyle),
  403. shadowColor: textStyle.shadowColor,
  404. shadowBlur: textStyle.shadowBlur,
  405. shadowOffsetX: textStyle.shadowOffsetX,
  406. shadowOffsetY: textStyle.shadowOffsetY
  407. }
  408. }));
  409. }
  410. },
  411. _buildDetail: function (seriesIndex) {
  412. var serie = this.series[seriesIndex];
  413. if (!serie.detail.show) {
  414. return;
  415. }
  416. var detail = serie.detail;
  417. var offsetCenter = detail.offsetCenter;
  418. var color = detail.backgroundColor;
  419. var textStyle = detail.textStyle;
  420. var textColor = textStyle.color;
  421. var params = this._paramsMap[seriesIndex];
  422. var value = this._getValue(seriesIndex);
  423. var x = params.center[0] - detail.width / 2 + this.parsePercent(offsetCenter[0], params.radius[1]);
  424. var y = params.center[1] + this.parsePercent(offsetCenter[1], params.radius[1]);
  425. this.shapeList.push(new RectangleShape({
  426. zlevel: this.getZlevelBase(),
  427. z: this.getZBase() + (Math.abs(x + detail.width / 2 - params.center[0]) + Math.abs(y + detail.height / 2 - params.center[1]) < textStyle.fontSize ? 2 : 1),
  428. hoverable: false,
  429. style: {
  430. x: x,
  431. y: y,
  432. width: detail.width,
  433. height: detail.height,
  434. brushType: 'both',
  435. color: color === 'auto' ? this._getColor(seriesIndex, value) : color,
  436. lineWidth: detail.borderWidth,
  437. strokeColor: detail.borderColor,
  438. shadowColor: detail.shadowColor,
  439. shadowBlur: detail.shadowBlur,
  440. shadowOffsetX: detail.shadowOffsetX,
  441. shadowOffsetY: detail.shadowOffsetY,
  442. text: this._getLabelText(detail.formatter, value),
  443. textFont: this.getFont(textStyle),
  444. textPosition: 'inside',
  445. textColor: textColor === 'auto' ? this._getColor(seriesIndex, value) : textColor
  446. }
  447. }));
  448. },
  449. _getValue: function (seriesIndex) {
  450. return this.getDataFromOption(this.series[seriesIndex].data[0]);
  451. },
  452. _colorMap: function (seriesIndex) {
  453. var serie = this.series[seriesIndex];
  454. var min = serie.min;
  455. var total = serie.max - min;
  456. var color = serie.axisLine.lineStyle.color;
  457. if (!(color instanceof Array)) {
  458. color = [[
  459. 1,
  460. color
  461. ]];
  462. }
  463. var colorArray = [];
  464. for (var i = 0, l = color.length; i < l; i++) {
  465. colorArray.push([
  466. color[i][0] * total + min,
  467. color[i][1]
  468. ]);
  469. }
  470. this._paramsMap[seriesIndex].colorArray = colorArray;
  471. },
  472. _getColor: function (seriesIndex, value) {
  473. if (value == null) {
  474. value = this._getValue(seriesIndex);
  475. }
  476. var colorArray = this._paramsMap[seriesIndex].colorArray;
  477. for (var i = 0, l = colorArray.length; i < l; i++) {
  478. if (colorArray[i][0] >= value) {
  479. return colorArray[i][1];
  480. }
  481. }
  482. return colorArray[colorArray.length - 1][1];
  483. },
  484. _getSector: function (center, r0, r, startAngle, endAngle, color, lineStyle) {
  485. return new SectorShape({
  486. zlevel: this.getZlevelBase(),
  487. z: this.getZBase(),
  488. hoverable: false,
  489. style: {
  490. x: center[0],
  491. y: center[1],
  492. r0: r0,
  493. r: r,
  494. startAngle: startAngle,
  495. endAngle: endAngle,
  496. brushType: 'fill',
  497. color: color,
  498. shadowColor: lineStyle.shadowColor,
  499. shadowBlur: lineStyle.shadowBlur,
  500. shadowOffsetX: lineStyle.shadowOffsetX,
  501. shadowOffsetY: lineStyle.shadowOffsetY
  502. }
  503. });
  504. },
  505. _getLabelText: function (formatter, value) {
  506. if (formatter) {
  507. if (typeof formatter === 'function') {
  508. return formatter.call(this.myChart, value);
  509. } else if (typeof formatter === 'string') {
  510. return formatter.replace('{value}', value);
  511. }
  512. }
  513. return value;
  514. },
  515. refresh: function (newOption) {
  516. if (newOption) {
  517. this.option = newOption;
  518. this.series = newOption.series;
  519. }
  520. this.backupShapeList();
  521. this._buildShape();
  522. }
  523. };
  524. zrUtil.inherits(Gauge, ChartBase);
  525. require('../chart').define('gauge', Gauge);
  526. return Gauge;
  527. });define('echarts/util/shape/GaugePointer', [
  528. 'require',
  529. 'zrender/shape/Base',
  530. 'zrender/tool/util',
  531. './normalIsCover'
  532. ], function (require) {
  533. var Base = require('zrender/shape/Base');
  534. var zrUtil = require('zrender/tool/util');
  535. function GaugePointer(options) {
  536. Base.call(this, options);
  537. }
  538. GaugePointer.prototype = {
  539. type: 'gauge-pointer',
  540. buildPath: function (ctx, style) {
  541. var r = style.r;
  542. var width = style.width;
  543. var angle = style.angle;
  544. var x = style.x - Math.cos(angle) * width * (width >= r / 3 ? 1 : 2);
  545. var y = style.y + Math.sin(angle) * width * (width >= r / 3 ? 1 : 2);
  546. angle = style.angle - Math.PI / 2;
  547. ctx.moveTo(x, y);
  548. ctx.lineTo(style.x + Math.cos(angle) * width, style.y - Math.sin(angle) * width);
  549. ctx.lineTo(style.x + Math.cos(style.angle) * r, style.y - Math.sin(style.angle) * r);
  550. ctx.lineTo(style.x - Math.cos(angle) * width, style.y + Math.sin(angle) * width);
  551. ctx.lineTo(x, y);
  552. return;
  553. },
  554. getRect: function (style) {
  555. if (style.__rect) {
  556. return style.__rect;
  557. }
  558. var width = style.width * 2;
  559. var xStart = style.x;
  560. var yStart = style.y;
  561. var xEnd = xStart + Math.cos(style.angle) * style.r;
  562. var yEnd = yStart - Math.sin(style.angle) * style.r;
  563. style.__rect = {
  564. x: Math.min(xStart, xEnd) - width,
  565. y: Math.min(yStart, yEnd) - width,
  566. width: Math.abs(xStart - xEnd) + width,
  567. height: Math.abs(yStart - yEnd) + width
  568. };
  569. return style.__rect;
  570. },
  571. isCover: require('./normalIsCover')
  572. };
  573. zrUtil.inherits(GaugePointer, Base);
  574. return GaugePointer;
  575. });