grid.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. import CLASS from './class'
  2. import { ChartInternal } from './core'
  3. import { isValue } from './util'
  4. ChartInternal.prototype.initGrid = function() {
  5. var $$ = this,
  6. config = $$.config,
  7. d3 = $$.d3
  8. $$.grid = $$.main
  9. .append('g')
  10. .attr('clip-path', $$.clipPathForGrid)
  11. .attr('class', CLASS.grid)
  12. if (config.grid_x_show) {
  13. $$.grid.append('g').attr('class', CLASS.xgrids)
  14. }
  15. if (config.grid_y_show) {
  16. $$.grid.append('g').attr('class', CLASS.ygrids)
  17. }
  18. if (config.grid_focus_show) {
  19. $$.grid
  20. .append('g')
  21. .attr('class', CLASS.xgridFocus)
  22. .append('line')
  23. .attr('class', CLASS.xgridFocus)
  24. }
  25. $$.xgrid = d3.selectAll([])
  26. if (!config.grid_lines_front) {
  27. $$.initGridLines()
  28. }
  29. }
  30. ChartInternal.prototype.initGridLines = function() {
  31. var $$ = this,
  32. d3 = $$.d3
  33. $$.gridLines = $$.main
  34. .append('g')
  35. .attr('clip-path', $$.clipPathForGrid)
  36. .attr('class', CLASS.grid + ' ' + CLASS.gridLines)
  37. $$.gridLines.append('g').attr('class', CLASS.xgridLines)
  38. $$.gridLines.append('g').attr('class', CLASS.ygridLines)
  39. $$.xgridLines = d3.selectAll([])
  40. }
  41. ChartInternal.prototype.updateXGrid = function(withoutUpdate) {
  42. var $$ = this,
  43. config = $$.config,
  44. d3 = $$.d3,
  45. xgridData = $$.generateGridData(config.grid_x_type, $$.x),
  46. tickOffset = $$.isCategorized() ? $$.xAxis.tickOffset() : 0
  47. $$.xgridAttr = config.axis_rotated
  48. ? {
  49. x1: 0,
  50. x2: $$.width,
  51. y1: function(d) {
  52. return $$.x(d) - tickOffset
  53. },
  54. y2: function(d) {
  55. return $$.x(d) - tickOffset
  56. }
  57. }
  58. : {
  59. x1: function(d) {
  60. return $$.x(d) + tickOffset
  61. },
  62. x2: function(d) {
  63. return $$.x(d) + tickOffset
  64. },
  65. y1: 0,
  66. y2: $$.height
  67. }
  68. $$.xgridAttr.opacity = function() {
  69. var pos = +d3.select(this).attr(config.axis_rotated ? 'y1' : 'x1')
  70. return pos === (config.axis_rotated ? $$.height : 0) ? 0 : 1
  71. }
  72. var xgrid = $$.main
  73. .select('.' + CLASS.xgrids)
  74. .selectAll('.' + CLASS.xgrid)
  75. .data(xgridData)
  76. var xgridEnter = xgrid
  77. .enter()
  78. .append('line')
  79. .attr('class', CLASS.xgrid)
  80. .attr('x1', $$.xgridAttr.x1)
  81. .attr('x2', $$.xgridAttr.x2)
  82. .attr('y1', $$.xgridAttr.y1)
  83. .attr('y2', $$.xgridAttr.y2)
  84. .style('opacity', 0)
  85. $$.xgrid = xgridEnter.merge(xgrid)
  86. if (!withoutUpdate) {
  87. $$.xgrid
  88. .attr('x1', $$.xgridAttr.x1)
  89. .attr('x2', $$.xgridAttr.x2)
  90. .attr('y1', $$.xgridAttr.y1)
  91. .attr('y2', $$.xgridAttr.y2)
  92. .style('opacity', $$.xgridAttr.opacity)
  93. }
  94. xgrid.exit().remove()
  95. }
  96. ChartInternal.prototype.updateYGrid = function() {
  97. var $$ = this,
  98. config = $$.config,
  99. gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks)
  100. var ygrid = $$.main
  101. .select('.' + CLASS.ygrids)
  102. .selectAll('.' + CLASS.ygrid)
  103. .data(gridValues)
  104. var ygridEnter = ygrid
  105. .enter()
  106. .append('line')
  107. // TODO: x1, x2, y1, y2, opacity need to be set here maybe
  108. .attr('class', CLASS.ygrid)
  109. $$.ygrid = ygridEnter.merge(ygrid)
  110. $$.ygrid
  111. .attr('x1', config.axis_rotated ? $$.y : 0)
  112. .attr('x2', config.axis_rotated ? $$.y : $$.width)
  113. .attr('y1', config.axis_rotated ? 0 : $$.y)
  114. .attr('y2', config.axis_rotated ? $$.height : $$.y)
  115. ygrid.exit().remove()
  116. $$.smoothLines($$.ygrid, 'grid')
  117. }
  118. ChartInternal.prototype.gridTextAnchor = function(d) {
  119. return d.position ? d.position : 'end'
  120. }
  121. ChartInternal.prototype.gridTextDx = function(d) {
  122. return d.position === 'start' ? 4 : d.position === 'middle' ? 0 : -4
  123. }
  124. ChartInternal.prototype.xGridTextX = function(d) {
  125. return d.position === 'start'
  126. ? -this.height
  127. : d.position === 'middle'
  128. ? -this.height / 2
  129. : 0
  130. }
  131. ChartInternal.prototype.yGridTextX = function(d) {
  132. return d.position === 'start'
  133. ? 0
  134. : d.position === 'middle'
  135. ? this.width / 2
  136. : this.width
  137. }
  138. ChartInternal.prototype.updateGrid = function(duration) {
  139. var $$ = this,
  140. main = $$.main,
  141. config = $$.config,
  142. xgridLine,
  143. xgridLineEnter,
  144. ygridLine,
  145. ygridLineEnter,
  146. xv = $$.xv.bind($$),
  147. yv = $$.yv.bind($$),
  148. xGridTextX = $$.xGridTextX.bind($$),
  149. yGridTextX = $$.yGridTextX.bind($$)
  150. // hide if arc type
  151. $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible')
  152. main.select('line.' + CLASS.xgridFocus).style('visibility', 'hidden')
  153. if (config.grid_x_show) {
  154. $$.updateXGrid()
  155. }
  156. xgridLine = main
  157. .select('.' + CLASS.xgridLines)
  158. .selectAll('.' + CLASS.xgridLine)
  159. .data(config.grid_x_lines)
  160. // enter
  161. xgridLineEnter = xgridLine
  162. .enter()
  163. .append('g')
  164. .attr('class', function(d) {
  165. return CLASS.xgridLine + (d['class'] ? ' ' + d['class'] : '')
  166. })
  167. xgridLineEnter
  168. .append('line')
  169. .attr('x1', config.axis_rotated ? 0 : xv)
  170. .attr('x2', config.axis_rotated ? $$.width : xv)
  171. .attr('y1', config.axis_rotated ? xv : 0)
  172. .attr('y2', config.axis_rotated ? xv : $$.height)
  173. .style('opacity', 0)
  174. xgridLineEnter
  175. .append('text')
  176. .attr('text-anchor', $$.gridTextAnchor)
  177. .attr('transform', config.axis_rotated ? '' : 'rotate(-90)')
  178. .attr('x', config.axis_rotated ? yGridTextX : xGridTextX)
  179. .attr('y', xv)
  180. .attr('dx', $$.gridTextDx)
  181. .attr('dy', -5)
  182. .style('opacity', 0)
  183. // udpate
  184. $$.xgridLines = xgridLineEnter.merge(xgridLine)
  185. // done in d3.transition() of the end of this function
  186. // exit
  187. xgridLine
  188. .exit()
  189. .transition()
  190. .duration(duration)
  191. .style('opacity', 0)
  192. .remove()
  193. // Y-Grid
  194. if (config.grid_y_show) {
  195. $$.updateYGrid()
  196. }
  197. ygridLine = main
  198. .select('.' + CLASS.ygridLines)
  199. .selectAll('.' + CLASS.ygridLine)
  200. .data(config.grid_y_lines)
  201. // enter
  202. ygridLineEnter = ygridLine
  203. .enter()
  204. .append('g')
  205. .attr('class', function(d) {
  206. return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : '')
  207. })
  208. ygridLineEnter
  209. .append('line')
  210. .attr('x1', config.axis_rotated ? yv : 0)
  211. .attr('x2', config.axis_rotated ? yv : $$.width)
  212. .attr('y1', config.axis_rotated ? 0 : yv)
  213. .attr('y2', config.axis_rotated ? $$.height : yv)
  214. .style('opacity', 0)
  215. ygridLineEnter
  216. .append('text')
  217. .attr('text-anchor', $$.gridTextAnchor)
  218. .attr('transform', config.axis_rotated ? 'rotate(-90)' : '')
  219. .attr('x', config.axis_rotated ? xGridTextX : yGridTextX)
  220. .attr('y', yv)
  221. .attr('dx', $$.gridTextDx)
  222. .attr('dy', -5)
  223. .style('opacity', 0)
  224. // update
  225. $$.ygridLines = ygridLineEnter.merge(ygridLine)
  226. $$.ygridLines
  227. .select('line')
  228. .transition()
  229. .duration(duration)
  230. .attr('x1', config.axis_rotated ? yv : 0)
  231. .attr('x2', config.axis_rotated ? yv : $$.width)
  232. .attr('y1', config.axis_rotated ? 0 : yv)
  233. .attr('y2', config.axis_rotated ? $$.height : yv)
  234. .style('opacity', 1)
  235. $$.ygridLines
  236. .select('text')
  237. .transition()
  238. .duration(duration)
  239. .attr(
  240. 'x',
  241. config.axis_rotated ? $$.xGridTextX.bind($$) : $$.yGridTextX.bind($$)
  242. )
  243. .attr('y', yv)
  244. .text(function(d) {
  245. return d.text
  246. })
  247. .style('opacity', 1)
  248. // exit
  249. ygridLine
  250. .exit()
  251. .transition()
  252. .duration(duration)
  253. .style('opacity', 0)
  254. .remove()
  255. }
  256. ChartInternal.prototype.redrawGrid = function(withTransition, transition) {
  257. var $$ = this,
  258. config = $$.config,
  259. xv = $$.xv.bind($$),
  260. lines = $$.xgridLines.select('line'),
  261. texts = $$.xgridLines.select('text')
  262. return [
  263. (withTransition ? lines.transition(transition) : lines)
  264. .attr('x1', config.axis_rotated ? 0 : xv)
  265. .attr('x2', config.axis_rotated ? $$.width : xv)
  266. .attr('y1', config.axis_rotated ? xv : 0)
  267. .attr('y2', config.axis_rotated ? xv : $$.height)
  268. .style('opacity', 1),
  269. (withTransition ? texts.transition(transition) : texts)
  270. .attr(
  271. 'x',
  272. config.axis_rotated ? $$.yGridTextX.bind($$) : $$.xGridTextX.bind($$)
  273. )
  274. .attr('y', xv)
  275. .text(function(d) {
  276. return d.text
  277. })
  278. .style('opacity', 1)
  279. ]
  280. }
  281. ChartInternal.prototype.showXGridFocus = function(selectedData) {
  282. var $$ = this,
  283. config = $$.config,
  284. dataToShow = selectedData.filter(function(d) {
  285. return d && isValue(d.value)
  286. }),
  287. focusEl = $$.main.selectAll('line.' + CLASS.xgridFocus),
  288. xx = $$.xx.bind($$)
  289. if (!config.tooltip_show) {
  290. return
  291. }
  292. // Hide when stanford plot exists
  293. if ($$.hasType('stanford') || $$.hasArcType()) {
  294. return
  295. }
  296. focusEl
  297. .style('visibility', 'visible')
  298. .data([dataToShow[0]])
  299. .attr(config.axis_rotated ? 'y1' : 'x1', xx)
  300. .attr(config.axis_rotated ? 'y2' : 'x2', xx)
  301. $$.smoothLines(focusEl, 'grid')
  302. }
  303. ChartInternal.prototype.hideXGridFocus = function() {
  304. this.main.select('line.' + CLASS.xgridFocus).style('visibility', 'hidden')
  305. }
  306. ChartInternal.prototype.updateXgridFocus = function() {
  307. var $$ = this,
  308. config = $$.config
  309. $$.main
  310. .select('line.' + CLASS.xgridFocus)
  311. .attr('x1', config.axis_rotated ? 0 : -10)
  312. .attr('x2', config.axis_rotated ? $$.width : -10)
  313. .attr('y1', config.axis_rotated ? -10 : 0)
  314. .attr('y2', config.axis_rotated ? -10 : $$.height)
  315. }
  316. ChartInternal.prototype.generateGridData = function(type, scale) {
  317. var $$ = this,
  318. gridData = [],
  319. xDomain,
  320. firstYear,
  321. lastYear,
  322. i,
  323. tickNum = $$.main
  324. .select('.' + CLASS.axisX)
  325. .selectAll('.tick')
  326. .size()
  327. if (type === 'year') {
  328. xDomain = $$.getXDomain()
  329. firstYear = xDomain[0].getFullYear()
  330. lastYear = xDomain[1].getFullYear()
  331. for (i = firstYear; i <= lastYear; i++) {
  332. gridData.push(new Date(i + '-01-01 00:00:00'))
  333. }
  334. } else {
  335. gridData = scale.ticks(10)
  336. if (gridData.length > tickNum) {
  337. // use only int
  338. gridData = gridData.filter(function(d) {
  339. return ('' + d).indexOf('.') < 0
  340. })
  341. }
  342. }
  343. return gridData
  344. }
  345. ChartInternal.prototype.getGridFilterToRemove = function(params) {
  346. return params
  347. ? function(line) {
  348. var found = false
  349. ;[].concat(params).forEach(function(param) {
  350. if (
  351. ('value' in param && line.value === param.value) ||
  352. ('class' in param && line['class'] === param['class'])
  353. ) {
  354. found = true
  355. }
  356. })
  357. return found
  358. }
  359. : function() {
  360. return true
  361. }
  362. }
  363. ChartInternal.prototype.removeGridLines = function(params, forX) {
  364. var $$ = this,
  365. config = $$.config,
  366. toRemove = $$.getGridFilterToRemove(params),
  367. toShow = function(line) {
  368. return !toRemove(line)
  369. },
  370. classLines = forX ? CLASS.xgridLines : CLASS.ygridLines,
  371. classLine = forX ? CLASS.xgridLine : CLASS.ygridLine
  372. $$.main
  373. .select('.' + classLines)
  374. .selectAll('.' + classLine)
  375. .filter(toRemove)
  376. .transition()
  377. .duration(config.transition_duration)
  378. .style('opacity', 0)
  379. .remove()
  380. if (forX) {
  381. config.grid_x_lines = config.grid_x_lines.filter(toShow)
  382. } else {
  383. config.grid_y_lines = config.grid_y_lines.filter(toShow)
  384. }
  385. }