CalendarView.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. var echarts = require("../../echarts");
  20. var zrUtil = require("zrender/lib/core/util");
  21. var graphic = require("../../util/graphic");
  22. var formatUtil = require("../../util/format");
  23. var numberUtil = require("../../util/number");
  24. /*
  25. * Licensed to the Apache Software Foundation (ASF) under one
  26. * or more contributor license agreements. See the NOTICE file
  27. * distributed with this work for additional information
  28. * regarding copyright ownership. The ASF licenses this file
  29. * to you under the Apache License, Version 2.0 (the
  30. * "License"); you may not use this file except in compliance
  31. * with the License. You may obtain a copy of the License at
  32. *
  33. * http://www.apache.org/licenses/LICENSE-2.0
  34. *
  35. * Unless required by applicable law or agreed to in writing,
  36. * software distributed under the License is distributed on an
  37. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  38. * KIND, either express or implied. See the License for the
  39. * specific language governing permissions and limitations
  40. * under the License.
  41. */
  42. var MONTH_TEXT = {
  43. EN: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
  44. CN: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
  45. };
  46. var WEEK_TEXT = {
  47. EN: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
  48. CN: ['日', '一', '二', '三', '四', '五', '六']
  49. };
  50. var _default = echarts.extendComponentView({
  51. type: 'calendar',
  52. /**
  53. * top/left line points
  54. * @private
  55. */
  56. _tlpoints: null,
  57. /**
  58. * bottom/right line points
  59. * @private
  60. */
  61. _blpoints: null,
  62. /**
  63. * first day of month
  64. * @private
  65. */
  66. _firstDayOfMonth: null,
  67. /**
  68. * first day point of month
  69. * @private
  70. */
  71. _firstDayPoints: null,
  72. render: function (calendarModel, ecModel, api) {
  73. var group = this.group;
  74. group.removeAll();
  75. var coordSys = calendarModel.coordinateSystem; // range info
  76. var rangeData = coordSys.getRangeInfo();
  77. var orient = coordSys.getOrient();
  78. this._renderDayRect(calendarModel, rangeData, group); // _renderLines must be called prior to following function
  79. this._renderLines(calendarModel, rangeData, orient, group);
  80. this._renderYearText(calendarModel, rangeData, orient, group);
  81. this._renderMonthText(calendarModel, orient, group);
  82. this._renderWeekText(calendarModel, rangeData, orient, group);
  83. },
  84. // render day rect
  85. _renderDayRect: function (calendarModel, rangeData, group) {
  86. var coordSys = calendarModel.coordinateSystem;
  87. var itemRectStyleModel = calendarModel.getModel('itemStyle').getItemStyle();
  88. var sw = coordSys.getCellWidth();
  89. var sh = coordSys.getCellHeight();
  90. for (var i = rangeData.start.time; i <= rangeData.end.time; i = coordSys.getNextNDay(i, 1).time) {
  91. var point = coordSys.dataToRect([i], false).tl; // every rect
  92. var rect = new graphic.Rect({
  93. shape: {
  94. x: point[0],
  95. y: point[1],
  96. width: sw,
  97. height: sh
  98. },
  99. cursor: 'default',
  100. style: itemRectStyleModel
  101. });
  102. group.add(rect);
  103. }
  104. },
  105. // render separate line
  106. _renderLines: function (calendarModel, rangeData, orient, group) {
  107. var self = this;
  108. var coordSys = calendarModel.coordinateSystem;
  109. var lineStyleModel = calendarModel.getModel('splitLine.lineStyle').getLineStyle();
  110. var show = calendarModel.get('splitLine.show');
  111. var lineWidth = lineStyleModel.lineWidth;
  112. this._tlpoints = [];
  113. this._blpoints = [];
  114. this._firstDayOfMonth = [];
  115. this._firstDayPoints = [];
  116. var firstDay = rangeData.start;
  117. for (var i = 0; firstDay.time <= rangeData.end.time; i++) {
  118. addPoints(firstDay.formatedDate);
  119. if (i === 0) {
  120. firstDay = coordSys.getDateInfo(rangeData.start.y + '-' + rangeData.start.m);
  121. }
  122. var date = firstDay.date;
  123. date.setMonth(date.getMonth() + 1);
  124. firstDay = coordSys.getDateInfo(date);
  125. }
  126. addPoints(coordSys.getNextNDay(rangeData.end.time, 1).formatedDate);
  127. function addPoints(date) {
  128. self._firstDayOfMonth.push(coordSys.getDateInfo(date));
  129. self._firstDayPoints.push(coordSys.dataToRect([date], false).tl);
  130. var points = self._getLinePointsOfOneWeek(calendarModel, date, orient);
  131. self._tlpoints.push(points[0]);
  132. self._blpoints.push(points[points.length - 1]);
  133. show && self._drawSplitline(points, lineStyleModel, group);
  134. } // render top/left line
  135. show && this._drawSplitline(self._getEdgesPoints(self._tlpoints, lineWidth, orient), lineStyleModel, group); // render bottom/right line
  136. show && this._drawSplitline(self._getEdgesPoints(self._blpoints, lineWidth, orient), lineStyleModel, group);
  137. },
  138. // get points at both ends
  139. _getEdgesPoints: function (points, lineWidth, orient) {
  140. var rs = [points[0].slice(), points[points.length - 1].slice()];
  141. var idx = orient === 'horizontal' ? 0 : 1; // both ends of the line are extend half lineWidth
  142. rs[0][idx] = rs[0][idx] - lineWidth / 2;
  143. rs[1][idx] = rs[1][idx] + lineWidth / 2;
  144. return rs;
  145. },
  146. // render split line
  147. _drawSplitline: function (points, lineStyleModel, group) {
  148. var poyline = new graphic.Polyline({
  149. z2: 20,
  150. shape: {
  151. points: points
  152. },
  153. style: lineStyleModel
  154. });
  155. group.add(poyline);
  156. },
  157. // render month line of one week points
  158. _getLinePointsOfOneWeek: function (calendarModel, date, orient) {
  159. var coordSys = calendarModel.coordinateSystem;
  160. date = coordSys.getDateInfo(date);
  161. var points = [];
  162. for (var i = 0; i < 7; i++) {
  163. var tmpD = coordSys.getNextNDay(date.time, i);
  164. var point = coordSys.dataToRect([tmpD.time], false);
  165. points[2 * tmpD.day] = point.tl;
  166. points[2 * tmpD.day + 1] = point[orient === 'horizontal' ? 'bl' : 'tr'];
  167. }
  168. return points;
  169. },
  170. _formatterLabel: function (formatter, params) {
  171. if (typeof formatter === 'string' && formatter) {
  172. return formatUtil.formatTplSimple(formatter, params);
  173. }
  174. if (typeof formatter === 'function') {
  175. return formatter(params);
  176. }
  177. return params.nameMap;
  178. },
  179. _yearTextPositionControl: function (textEl, point, orient, position, margin) {
  180. point = point.slice();
  181. var aligns = ['center', 'bottom'];
  182. if (position === 'bottom') {
  183. point[1] += margin;
  184. aligns = ['center', 'top'];
  185. } else if (position === 'left') {
  186. point[0] -= margin;
  187. } else if (position === 'right') {
  188. point[0] += margin;
  189. aligns = ['center', 'top'];
  190. } else {
  191. // top
  192. point[1] -= margin;
  193. }
  194. var rotate = 0;
  195. if (position === 'left' || position === 'right') {
  196. rotate = Math.PI / 2;
  197. }
  198. return {
  199. rotation: rotate,
  200. position: point,
  201. style: {
  202. textAlign: aligns[0],
  203. textVerticalAlign: aligns[1]
  204. }
  205. };
  206. },
  207. // render year
  208. _renderYearText: function (calendarModel, rangeData, orient, group) {
  209. var yearLabel = calendarModel.getModel('yearLabel');
  210. if (!yearLabel.get('show')) {
  211. return;
  212. }
  213. var margin = yearLabel.get('margin');
  214. var pos = yearLabel.get('position');
  215. if (!pos) {
  216. pos = orient !== 'horizontal' ? 'top' : 'left';
  217. }
  218. var points = [this._tlpoints[this._tlpoints.length - 1], this._blpoints[0]];
  219. var xc = (points[0][0] + points[1][0]) / 2;
  220. var yc = (points[0][1] + points[1][1]) / 2;
  221. var idx = orient === 'horizontal' ? 0 : 1;
  222. var posPoints = {
  223. top: [xc, points[idx][1]],
  224. bottom: [xc, points[1 - idx][1]],
  225. left: [points[1 - idx][0], yc],
  226. right: [points[idx][0], yc]
  227. };
  228. var name = rangeData.start.y;
  229. if (+rangeData.end.y > +rangeData.start.y) {
  230. name = name + '-' + rangeData.end.y;
  231. }
  232. var formatter = yearLabel.get('formatter');
  233. var params = {
  234. start: rangeData.start.y,
  235. end: rangeData.end.y,
  236. nameMap: name
  237. };
  238. var content = this._formatterLabel(formatter, params);
  239. var yearText = new graphic.Text({
  240. z2: 30
  241. });
  242. graphic.setTextStyle(yearText.style, yearLabel, {
  243. text: content
  244. }), yearText.attr(this._yearTextPositionControl(yearText, posPoints[pos], orient, pos, margin));
  245. group.add(yearText);
  246. },
  247. _monthTextPositionControl: function (point, isCenter, orient, position, margin) {
  248. var align = 'left';
  249. var vAlign = 'top';
  250. var x = point[0];
  251. var y = point[1];
  252. if (orient === 'horizontal') {
  253. y = y + margin;
  254. if (isCenter) {
  255. align = 'center';
  256. }
  257. if (position === 'start') {
  258. vAlign = 'bottom';
  259. }
  260. } else {
  261. x = x + margin;
  262. if (isCenter) {
  263. vAlign = 'middle';
  264. }
  265. if (position === 'start') {
  266. align = 'right';
  267. }
  268. }
  269. return {
  270. x: x,
  271. y: y,
  272. textAlign: align,
  273. textVerticalAlign: vAlign
  274. };
  275. },
  276. // render month and year text
  277. _renderMonthText: function (calendarModel, orient, group) {
  278. var monthLabel = calendarModel.getModel('monthLabel');
  279. if (!monthLabel.get('show')) {
  280. return;
  281. }
  282. var nameMap = monthLabel.get('nameMap');
  283. var margin = monthLabel.get('margin');
  284. var pos = monthLabel.get('position');
  285. var align = monthLabel.get('align');
  286. var termPoints = [this._tlpoints, this._blpoints];
  287. if (zrUtil.isString(nameMap)) {
  288. nameMap = MONTH_TEXT[nameMap.toUpperCase()] || [];
  289. }
  290. var idx = pos === 'start' ? 0 : 1;
  291. var axis = orient === 'horizontal' ? 0 : 1;
  292. margin = pos === 'start' ? -margin : margin;
  293. var isCenter = align === 'center';
  294. for (var i = 0; i < termPoints[idx].length - 1; i++) {
  295. var tmp = termPoints[idx][i].slice();
  296. var firstDay = this._firstDayOfMonth[i];
  297. if (isCenter) {
  298. var firstDayPoints = this._firstDayPoints[i];
  299. tmp[axis] = (firstDayPoints[axis] + termPoints[0][i + 1][axis]) / 2;
  300. }
  301. var formatter = monthLabel.get('formatter');
  302. var name = nameMap[+firstDay.m - 1];
  303. var params = {
  304. yyyy: firstDay.y,
  305. yy: (firstDay.y + '').slice(2),
  306. MM: firstDay.m,
  307. M: +firstDay.m,
  308. nameMap: name
  309. };
  310. var content = this._formatterLabel(formatter, params);
  311. var monthText = new graphic.Text({
  312. z2: 30
  313. });
  314. zrUtil.extend(graphic.setTextStyle(monthText.style, monthLabel, {
  315. text: content
  316. }), this._monthTextPositionControl(tmp, isCenter, orient, pos, margin));
  317. group.add(monthText);
  318. }
  319. },
  320. _weekTextPositionControl: function (point, orient, position, margin, cellSize) {
  321. var align = 'center';
  322. var vAlign = 'middle';
  323. var x = point[0];
  324. var y = point[1];
  325. var isStart = position === 'start';
  326. if (orient === 'horizontal') {
  327. x = x + margin + (isStart ? 1 : -1) * cellSize[0] / 2;
  328. align = isStart ? 'right' : 'left';
  329. } else {
  330. y = y + margin + (isStart ? 1 : -1) * cellSize[1] / 2;
  331. vAlign = isStart ? 'bottom' : 'top';
  332. }
  333. return {
  334. x: x,
  335. y: y,
  336. textAlign: align,
  337. textVerticalAlign: vAlign
  338. };
  339. },
  340. // render weeks
  341. _renderWeekText: function (calendarModel, rangeData, orient, group) {
  342. var dayLabel = calendarModel.getModel('dayLabel');
  343. if (!dayLabel.get('show')) {
  344. return;
  345. }
  346. var coordSys = calendarModel.coordinateSystem;
  347. var pos = dayLabel.get('position');
  348. var nameMap = dayLabel.get('nameMap');
  349. var margin = dayLabel.get('margin');
  350. var firstDayOfWeek = coordSys.getFirstDayOfWeek();
  351. if (zrUtil.isString(nameMap)) {
  352. nameMap = WEEK_TEXT[nameMap.toUpperCase()] || [];
  353. }
  354. var start = coordSys.getNextNDay(rangeData.end.time, 7 - rangeData.lweek).time;
  355. var cellSize = [coordSys.getCellWidth(), coordSys.getCellHeight()];
  356. margin = numberUtil.parsePercent(margin, cellSize[orient === 'horizontal' ? 0 : 1]);
  357. if (pos === 'start') {
  358. start = coordSys.getNextNDay(rangeData.start.time, -(7 + rangeData.fweek)).time;
  359. margin = -margin;
  360. }
  361. for (var i = 0; i < 7; i++) {
  362. var tmpD = coordSys.getNextNDay(start, i);
  363. var point = coordSys.dataToRect([tmpD.time], false).center;
  364. var day = i;
  365. day = Math.abs((i + firstDayOfWeek) % 7);
  366. var weekText = new graphic.Text({
  367. z2: 30
  368. });
  369. zrUtil.extend(graphic.setTextStyle(weekText.style, dayLabel, {
  370. text: nameMap[day]
  371. }), this._weekTextPositionControl(point, orient, pos, margin, cellSize));
  372. group.add(weekText);
  373. }
  374. }
  375. });
  376. module.exports = _default;