gauge.js 23 KB

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