a0607eeb31990637c50a152b7c88f0d486f73489.svn-base 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /**
  2. * echarts组件类: 坐标轴
  3. *
  4. * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
  5. * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
  6. *
  7. * 直角坐标系中坐标轴数组,数组中每一项代表一条横轴(纵轴)坐标轴。
  8. * 标准(1.0)中规定最多同时存在2条横轴和2条纵轴
  9. * 单条横轴时可指定安放于grid的底部(默认)或顶部,2条同时存在时则默认第一条安放于底部,第二天安放于顶部
  10. * 单条纵轴时可指定安放于grid的左侧(默认)或右侧,2条同时存在时则默认第一条安放于左侧,第二天安放于右侧。
  11. * 坐标轴有两种类型,类目型和数值型(区别详见axis):
  12. * 横轴通常为类目型,但条形图时则横轴为数值型,散点图时则横纵均为数值型
  13. * 纵轴通常为数值型,但条形图时则纵轴为类目型。
  14. *
  15. */
  16. define(function (require) {
  17. var Base = require('./base');
  18. var LineShape = require('zrender/shape/Line');
  19. var ecConfig = require('../config');
  20. var ecData = require('../util/ecData');
  21. var zrUtil = require('zrender/tool/util');
  22. var zrColor = require('zrender/tool/color');
  23. /**
  24. * 构造函数
  25. * @param {Object} messageCenter echart消息中心
  26. * @param {ZRender} zr zrender实例
  27. * @param {Object} option 图表选项
  28. * @param {string=} option.xAxis.type 坐标轴类型,横轴默认为类目型'category'
  29. * @param {string=} option.yAxis.type 坐标轴类型,纵轴默认为类目型'value'
  30. * @param {Object} component 组件
  31. * @param {string} axisType 横走or纵轴
  32. */
  33. function Axis(ecTheme, messageCenter, zr, option, myChart, axisType) {
  34. Base.call(this, ecTheme, messageCenter, zr, option, myChart);
  35. this.axisType = axisType;
  36. this._axisList = [];
  37. this.refresh(option);
  38. }
  39. Axis.prototype = {
  40. type: ecConfig.COMPONENT_TYPE_AXIS,
  41. axisBase: {
  42. // 轴线
  43. _buildAxisLine: function () {
  44. var lineWidth = this.option.axisLine.lineStyle.width;
  45. var halfLineWidth = lineWidth / 2;
  46. var axShape = {
  47. _axisShape: 'axisLine',
  48. zlevel: this.getZlevelBase(),
  49. z: this.getZBase() + 3,
  50. hoverable: false
  51. };
  52. var grid = this.grid;
  53. switch (this.option.position) {
  54. case 'left' :
  55. axShape.style = {
  56. xStart: grid.getX() - halfLineWidth,
  57. yStart: grid.getYend(),
  58. xEnd: grid.getX() - halfLineWidth,
  59. yEnd: grid.getY(),
  60. lineCap: 'round'
  61. };
  62. break;
  63. case 'right' :
  64. axShape.style = {
  65. xStart: grid.getXend() + halfLineWidth,
  66. yStart: grid.getYend(),
  67. xEnd: grid.getXend() + halfLineWidth,
  68. yEnd: grid.getY(),
  69. lineCap: 'round'
  70. };
  71. break;
  72. case 'bottom' :
  73. axShape.style = {
  74. xStart: grid.getX(),
  75. yStart: grid.getYend() + halfLineWidth,
  76. xEnd: grid.getXend(),
  77. yEnd: grid.getYend() + halfLineWidth,
  78. lineCap: 'round'
  79. };
  80. break;
  81. case 'top' :
  82. axShape.style = {
  83. xStart: grid.getX(),
  84. yStart: grid.getY() - halfLineWidth,
  85. xEnd: grid.getXend(),
  86. yEnd: grid.getY() - halfLineWidth,
  87. lineCap: 'round'
  88. };
  89. break;
  90. }
  91. var style = axShape.style;
  92. if (this.option.name !== '') { // 别帮我代码规范
  93. style.text = this.option.name;
  94. style.textPosition = this.option.nameLocation;
  95. style.textFont = this.getFont(this.option.nameTextStyle);
  96. if (this.option.nameTextStyle.align) {
  97. style.textAlign = this.option.nameTextStyle.align;
  98. }
  99. if (this.option.nameTextStyle.baseline) {
  100. style.textBaseline = this.option.nameTextStyle.baseline;
  101. }
  102. if (this.option.nameTextStyle.color) {
  103. style.textColor = this.option.nameTextStyle.color;
  104. }
  105. }
  106. style.strokeColor = this.option.axisLine.lineStyle.color;
  107. style.lineWidth = lineWidth;
  108. // 亚像素优化
  109. if (this.isHorizontal()) {
  110. // 横向布局,优化y
  111. style.yStart
  112. = style.yEnd
  113. = this.subPixelOptimize(style.yEnd, lineWidth);
  114. }
  115. else {
  116. // 纵向布局,优化x
  117. style.xStart
  118. = style.xEnd
  119. = this.subPixelOptimize(style.xEnd, lineWidth);
  120. }
  121. style.lineType = this.option.axisLine.lineStyle.type;
  122. axShape = new LineShape(axShape);
  123. this.shapeList.push(axShape);
  124. },
  125. _axisLabelClickable: function(clickable, axShape) {
  126. if (clickable) {
  127. ecData.pack(
  128. axShape, undefined, -1, undefined, -1, axShape.style.text
  129. );
  130. axShape.hoverable = true;
  131. axShape.clickable = true;
  132. axShape.highlightStyle = {
  133. color: zrColor.lift(axShape.style.color, 1),
  134. brushType: 'fill'
  135. };
  136. return axShape;
  137. }
  138. else {
  139. return axShape;
  140. }
  141. },
  142. refixAxisShape: function(zeroX, zeroY) {
  143. if (!this.option.axisLine.onZero) {
  144. return;
  145. }
  146. var tickLength;
  147. if (this.isHorizontal() && zeroY != null) {
  148. // 横向布局调整纵向y
  149. for (var i = 0, l = this.shapeList.length; i < l; i++) {
  150. if (this.shapeList[i]._axisShape === 'axisLine') {
  151. this.shapeList[i].style.yStart
  152. = this.shapeList[i].style.yEnd
  153. = this.subPixelOptimize(
  154. zeroY, this.shapeList[i].stylelineWidth
  155. );
  156. this.zr.modShape(this.shapeList[i].id);
  157. }
  158. else if (this.shapeList[i]._axisShape === 'axisTick') {
  159. tickLength = this.shapeList[i].style.yEnd
  160. - this.shapeList[i].style.yStart;
  161. this.shapeList[i].style.yStart = zeroY - tickLength;
  162. this.shapeList[i].style.yEnd = zeroY;
  163. this.zr.modShape(this.shapeList[i].id);
  164. }
  165. }
  166. }
  167. if (!this.isHorizontal() && zeroX != null) {
  168. // 纵向布局调整横向x
  169. for (var i = 0, l = this.shapeList.length; i < l; i++) {
  170. if (this.shapeList[i]._axisShape === 'axisLine') {
  171. this.shapeList[i].style.xStart
  172. = this.shapeList[i].style.xEnd
  173. = this.subPixelOptimize(
  174. zeroX, this.shapeList[i].stylelineWidth
  175. );
  176. this.zr.modShape(this.shapeList[i].id);
  177. }
  178. else if (this.shapeList[i]._axisShape === 'axisTick') {
  179. tickLength = this.shapeList[i].style.xEnd
  180. - this.shapeList[i].style.xStart;
  181. this.shapeList[i].style.xStart = zeroX;
  182. this.shapeList[i].style.xEnd = zeroX + tickLength;
  183. this.zr.modShape(this.shapeList[i].id);
  184. }
  185. }
  186. }
  187. },
  188. getPosition: function () {
  189. return this.option.position;
  190. },
  191. isHorizontal: function() {
  192. return this.option.position === 'bottom' || this.option.position === 'top';
  193. }
  194. },
  195. /**
  196. * 参数修正&默认值赋值,重载基类方法
  197. * @param {Object} opt 参数
  198. */
  199. reformOption: function (opt) {
  200. // 不写或传了个空数值默认为数值轴
  201. if (!opt || (opt instanceof Array && opt.length === 0)) {
  202. opt = [ { type: ecConfig.COMPONENT_TYPE_AXIS_VALUE } ];
  203. }
  204. else if (!(opt instanceof Array)){
  205. opt = [opt];
  206. }
  207. // 最多两条,其他参数忽略
  208. if (opt.length > 2) {
  209. opt = [opt[0], opt[1]];
  210. }
  211. if (this.axisType === 'xAxis') {
  212. // 横轴位置默认配置
  213. if (!opt[0].position // 没配置或配置错
  214. || (opt[0].position != 'bottom' && opt[0].position != 'top')
  215. ) {
  216. opt[0].position = 'bottom';
  217. }
  218. if (opt.length > 1) {
  219. opt[1].position = opt[0].position === 'bottom' ? 'top' : 'bottom';
  220. }
  221. for (var i = 0, l = opt.length; i < l; i++) {
  222. // 坐标轴类型,横轴默认为类目型'category'
  223. opt[i].type = opt[i].type || 'category';
  224. // 标识轴类型&索引
  225. opt[i].xAxisIndex = i;
  226. opt[i].yAxisIndex = -1;
  227. }
  228. }
  229. else {
  230. // 纵轴位置默认配置
  231. if (!opt[0].position // 没配置或配置错
  232. || (opt[0].position != 'left' && opt[0].position != 'right')
  233. ) {
  234. opt[0].position = 'left';
  235. }
  236. if (opt.length > 1) {
  237. opt[1].position = opt[0].position === 'left' ? 'right' : 'left';
  238. }
  239. for (var i = 0, l = opt.length; i < l; i++) {
  240. // 坐标轴类型,纵轴默认为数值型'value'
  241. opt[i].type = opt[i].type || 'value';
  242. // 标识轴类型&索引
  243. opt[i].xAxisIndex = -1;
  244. opt[i].yAxisIndex = i;
  245. }
  246. }
  247. return opt;
  248. },
  249. /**
  250. * 刷新
  251. */
  252. refresh: function (newOption) {
  253. var axisOption;
  254. if (newOption) {
  255. this.option = newOption;
  256. if (this.axisType === 'xAxis') {
  257. this.option.xAxis = this.reformOption(newOption.xAxis);
  258. axisOption = this.option.xAxis;
  259. }
  260. else {
  261. this.option.yAxis = this.reformOption(newOption.yAxis);
  262. axisOption = this.option.yAxis;
  263. }
  264. this.series = newOption.series;
  265. }
  266. var CategoryAxis = require('./categoryAxis');
  267. var ValueAxis = require('./valueAxis');
  268. var len = Math.max((axisOption && axisOption.length || 0), this._axisList.length);
  269. for (var i = 0; i < len; i++) {
  270. if (this._axisList[i] // 已有实例
  271. && newOption // 非空刷新
  272. && (!axisOption[i] || this._axisList[i].type != axisOption[i].type) // 类型不匹配
  273. ) {
  274. this._axisList[i].dispose && this._axisList[i].dispose();
  275. this._axisList[i] = false;
  276. }
  277. if (this._axisList[i]) {
  278. this._axisList[i].refresh && this._axisList[i].refresh(
  279. axisOption ? axisOption[i] : false,
  280. this.series
  281. );
  282. }
  283. else if (axisOption && axisOption[i]) {
  284. this._axisList[i] = axisOption[i].type === 'category'
  285. ? new CategoryAxis(
  286. this.ecTheme, this.messageCenter, this.zr,
  287. axisOption[i], this.myChart, this.axisBase
  288. )
  289. : new ValueAxis(
  290. this.ecTheme, this.messageCenter, this.zr,
  291. axisOption[i], this.myChart, this.axisBase,
  292. this.series
  293. );
  294. }
  295. }
  296. },
  297. /**
  298. * 根据值换算位置
  299. * @param {number} idx 坐标轴索引0~1
  300. */
  301. getAxis: function (idx) {
  302. return this._axisList[idx];
  303. },
  304. getAxisCount: function () {
  305. return this._axisList.length;
  306. },
  307. clear: function () {
  308. for (var i = 0, l = this._axisList.length; i < l; i++) {
  309. this._axisList[i].dispose && this._axisList[i].dispose();
  310. }
  311. this._axisList = [];
  312. }
  313. };
  314. zrUtil.inherits(Axis, Base);
  315. require('../component').define('axis', Axis);
  316. return Axis;
  317. });