interaction-spec.ts 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. import { d3, setMouseEvent, initChart } from './c3-helper'
  2. describe('c3 chart interaction', function() {
  3. 'use strict'
  4. var chart, args
  5. const moveMouseOut = () =>
  6. setMouseEvent(chart, 'mouseout', 0, 0, d3.select('.c3-event-rect').node())
  7. const moveMouse = (x = 0, y = 0) =>
  8. setMouseEvent(chart, 'mousemove', x, y, d3.select('.c3-event-rect').node())
  9. const clickMouse = (x = 0, y = 0) =>
  10. setMouseEvent(chart, 'click', x, y, d3.select('.c3-event-rect').node())
  11. beforeEach(function(done) {
  12. chart = initChart(chart, args, done)
  13. })
  14. describe('generate event rects', function() {
  15. describe('custom x', function() {
  16. beforeAll(function() {
  17. args = {
  18. data: {
  19. x: 'x',
  20. columns: [
  21. ['x', 0, 1000, 3000, 10000],
  22. ['data', 10, 10, 10, 10]
  23. ],
  24. type: 'bar'
  25. }
  26. }
  27. })
  28. it('should have only 1 event rect properly', function() {
  29. var eventRects = d3.selectAll('.c3-event-rect')
  30. expect(eventRects.size()).toBe(1)
  31. eventRects.each(function() {
  32. var box = (d3.select(this).node() as any).getBoundingClientRect()
  33. expect(box.left).toBeCloseTo(40.5, -2)
  34. expect(box.width).toBeCloseTo(598, -2)
  35. })
  36. })
  37. describe('mouseover', function() {
  38. let mouseoutCounter = 0
  39. let mouseoverCounter = 0
  40. beforeAll(function() {
  41. args = {
  42. data: {
  43. columns: [
  44. ['data1', 30, 200, 100, 400, -150, 250],
  45. ['data2', 50, 20, 10, 40, 15, 25],
  46. ['data3', -150, 120, 110, 140, 115, 125]
  47. ],
  48. type: 'bar',
  49. onmouseout: function() {
  50. mouseoutCounter += 1
  51. },
  52. onmouseover: function() {
  53. mouseoverCounter += 1
  54. }
  55. },
  56. axis: {
  57. rotated: false
  58. }
  59. }
  60. })
  61. beforeEach(function() {
  62. mouseoverCounter = 0
  63. mouseoutCounter = 0
  64. })
  65. it('should be undefined when not within bar', function() {
  66. moveMouseOut()
  67. expect(mouseoutCounter).toEqual(0)
  68. expect(mouseoverCounter).toEqual(0)
  69. expect(chart.internal.mouseover).toBeUndefined()
  70. })
  71. it('should be data value when within bar', function() {
  72. moveMouse(31, 280)
  73. expect(mouseoutCounter).toEqual(0)
  74. expect(mouseoverCounter).toEqual(1)
  75. expect(chart.internal.mouseover).toEqual({
  76. x: 0,
  77. value: 30,
  78. index: 0,
  79. id: 'data1',
  80. name: 'data1'
  81. })
  82. })
  83. it('should be undefined after leaving chart', function() {
  84. moveMouse(31, 280)
  85. moveMouseOut()
  86. expect(mouseoutCounter).toEqual(1)
  87. expect(mouseoverCounter).toEqual(1)
  88. expect(chart.internal.mouseover).toBeUndefined()
  89. })
  90. it('should retrigger mouseover event when returning to same value', function() {
  91. moveMouse(31, 280)
  92. moveMouseOut()
  93. moveMouse(31, 280)
  94. expect(mouseoutCounter).toEqual(1)
  95. expect(mouseoverCounter).toEqual(2)
  96. expect(chart.internal.mouseover).toEqual({
  97. x: 0,
  98. value: 30,
  99. index: 0,
  100. id: 'data1',
  101. name: 'data1'
  102. })
  103. })
  104. })
  105. describe('should generate bar chart with only one data', function() {
  106. beforeAll(function() {
  107. args = {
  108. data: {
  109. x: 'x',
  110. columns: [
  111. ['x', 0],
  112. ['data', 10]
  113. ],
  114. type: 'bar'
  115. }
  116. }
  117. })
  118. it('should have 1 event rects properly', function() {
  119. var eventRects = d3.selectAll('.c3-event-rect')
  120. expect(eventRects.size()).toBe(1)
  121. eventRects.each(function() {
  122. var box = (d3.select(this).node() as any).getBoundingClientRect()
  123. expect(box.left).toBeCloseTo(40.5, -2)
  124. expect(box.width).toBeCloseTo(598, -2)
  125. })
  126. })
  127. })
  128. })
  129. describe('timeseries', function() {
  130. beforeAll(function() {
  131. args = {
  132. data: {
  133. x: 'x',
  134. columns: [
  135. ['x', '20140101', '20140201', '20140210', '20140301'],
  136. ['data', 10, 10, 10, 10]
  137. ]
  138. }
  139. }
  140. })
  141. it('should have only 1 event rect properly', function() {
  142. var eventRects = d3.selectAll('.c3-event-rect')
  143. expect(eventRects.size()).toBe(1)
  144. eventRects.each(function() {
  145. var box = (d3.select(this).node() as any).getBoundingClientRect()
  146. expect(box.left).toBeCloseTo(40.5, -2)
  147. expect(box.width).toBeCloseTo(598, -2)
  148. })
  149. })
  150. describe('should generate line chart with only 1 data timeseries', function() {
  151. beforeAll(function() {
  152. args = {
  153. data: {
  154. x: 'x',
  155. columns: [
  156. ['x', '20140101'],
  157. ['data', 10]
  158. ]
  159. }
  160. }
  161. })
  162. it('should have 1 event rects properly', function() {
  163. var eventRects = d3.selectAll('.c3-event-rect')
  164. expect(eventRects.size()).toBe(1)
  165. eventRects.each(function() {
  166. var box = (d3.select(this).node() as any).getBoundingClientRect()
  167. expect(box.left).toBeCloseTo(40.5, -2)
  168. expect(box.width).toBeCloseTo(598, -2)
  169. })
  170. })
  171. })
  172. })
  173. })
  174. describe('bar chart', function() {
  175. describe('tooltip_grouped=true', function() {
  176. beforeAll(() => {
  177. args = {
  178. data: {
  179. columns: [
  180. ['data1', 30, 200, 200, 400, 150, -250],
  181. ['data2', 130, -100, 100, 200, 150, 50],
  182. ['data3', 230, -200, 200, 0, 250, 250]
  183. ],
  184. type: 'bar',
  185. groups: [['data1', 'data2']],
  186. hide: ['data1']
  187. },
  188. tooltip: {
  189. grouped: true
  190. },
  191. axis: {
  192. x: {
  193. type: 'category'
  194. },
  195. rotated: true
  196. },
  197. interaction: {
  198. enabled: true
  199. }
  200. }
  201. })
  202. it('generate a single rect', () => {
  203. const eventRectList = d3.selectAll('.c3-event-rect')
  204. expect(eventRectList.size()).toBe(1)
  205. expect(eventRectList.attr('x')).toEqual('0')
  206. expect(eventRectList.attr('y')).toEqual('0')
  207. expect(eventRectList.attr('height')).toEqual('' + chart.internal.height)
  208. expect(eventRectList.attr('width')).toEqual('' + chart.internal.width)
  209. })
  210. it('shows tooltip with visible data of currently hovered category', () => {
  211. moveMouse(20, 20)
  212. expect(
  213. (document.querySelector('.c3-tooltip-container') as any).style.display
  214. ).toEqual('block')
  215. const tooltipData = [
  216. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  217. ]
  218. expect(tooltipData.length).toBe(3) // header + data[123]
  219. expect(tooltipData[1].querySelector('.name').textContent).toBe('data3')
  220. expect(tooltipData[2].querySelector('.name').textContent).toBe('data2')
  221. })
  222. it('shows cursor:pointer only if hovering bar', () => {
  223. const eventRect = d3.select('.c3-event-rect')
  224. moveMouse(1, 1)
  225. expect(eventRect.style('cursor')).toEqual('auto')
  226. moveMouse(360, 48)
  227. expect(eventRect.style('cursor')).toEqual('pointer')
  228. moveMouse(1, 1)
  229. expect(eventRect.style('cursor')).toEqual('auto')
  230. })
  231. it('expands all bars of currently hovered category', () => {
  232. moveMouse(20, 20)
  233. const barList = d3.selectAll('.c3-bar')
  234. expect(barList.size()).toBeGreaterThan(0)
  235. barList.each(function() {
  236. if (
  237. (this as any).classList.contains('c3-bar-0') &&
  238. !(this as any).parentElement.classList.contains('c3-bars-data1')
  239. ) {
  240. expect((this as any).classList.contains('_expanded_')).toBeTruthy()
  241. } else {
  242. expect((this as any).classList.contains('_expanded_')).toBeFalsy()
  243. }
  244. })
  245. moveMouse(20, 170)
  246. barList.each(function() {
  247. if (
  248. (this as any).classList.contains('c3-bar-2') &&
  249. !(this as any).parentElement.classList.contains('c3-bars-data1')
  250. ) {
  251. expect((this as any).classList.contains('_expanded_')).toBeTruthy()
  252. } else {
  253. expect((this as any).classList.contains('_expanded_')).toBeFalsy()
  254. }
  255. })
  256. })
  257. })
  258. describe('tooltip_grouped=false', function() {
  259. beforeAll(() => {
  260. args = {
  261. data: {
  262. columns: [
  263. ['data1', 30, 200, 200, 400, 150, -250],
  264. ['data2', 130, -100, 100, 200, 150, 50],
  265. ['data3', 230, -200, 200, 0, 250, 250]
  266. ],
  267. type: 'bar',
  268. groups: [['data1', 'data2']]
  269. },
  270. tooltip: {
  271. grouped: false
  272. },
  273. axis: {
  274. x: {
  275. type: 'category'
  276. }
  277. },
  278. interaction: {
  279. enabled: true
  280. }
  281. }
  282. })
  283. it('generate a single rect', () => {
  284. const eventRectList = d3.selectAll('.c3-event-rect')
  285. expect(eventRectList.size()).toBe(1)
  286. expect(eventRectList.attr('x')).toEqual('0')
  287. expect(eventRectList.attr('y')).toEqual('0')
  288. expect(eventRectList.attr('height')).toEqual('' + chart.internal.height)
  289. expect(eventRectList.attr('width')).toEqual('' + chart.internal.width)
  290. })
  291. it('shows tooltip with only hovered data', () => {
  292. moveMouse(1, 1)
  293. expect(
  294. (document.querySelector('.c3-tooltip-container') as any).style.display
  295. ).toEqual('none')
  296. moveMouse(35, 268)
  297. expect(
  298. (document.querySelector('.c3-tooltip-container') as any).style.display
  299. ).toEqual('block')
  300. const tooltipData = [
  301. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  302. ]
  303. expect(tooltipData.length).toBe(2) // header + data2
  304. expect(tooltipData[1].querySelector('.name').textContent).toBe('data2')
  305. expect(tooltipData[1].querySelector('.value').textContent).toBe('130')
  306. })
  307. it('expands only hovered bar', () => {
  308. moveMouse(20, 20)
  309. const barList = d3.selectAll('.c3-bar')
  310. expect(barList.size()).toBeGreaterThan(0)
  311. // nothing expanded
  312. barList.each(function() {
  313. expect((this as any).classList.contains('_expanded_')).toBeFalsy()
  314. })
  315. moveMouse(38, 258)
  316. barList.each(function() {
  317. if (
  318. (this as any).classList.contains('c3-bar-0') &&
  319. (this as any).parentElement.classList.contains('c3-bars-data2')
  320. ) {
  321. expect((this as any).classList.contains('_expanded_')).toBeTruthy()
  322. } else {
  323. expect((this as any).classList.contains('_expanded_')).toBeFalsy()
  324. }
  325. })
  326. })
  327. })
  328. })
  329. describe('line chart', function() {
  330. describe('tooltip_grouped=false', function() {
  331. let clickedData = []
  332. beforeAll(() => {
  333. args = {
  334. data: {
  335. columns: [
  336. ['data1', 30, 200, 200, 400, 150, -250],
  337. ['data2', 130, -100, 100, 200, 150, 50],
  338. ['data3', 230, -200, 200, 0, 250, 250]
  339. ],
  340. type: 'line',
  341. groups: [['data1', 'data2']],
  342. onclick: function(d) {
  343. clickedData.push(d)
  344. }
  345. },
  346. tooltip: {
  347. grouped: false
  348. },
  349. axis: {
  350. x: {
  351. type: 'category'
  352. }
  353. },
  354. interaction: {
  355. enabled: true
  356. },
  357. point: {
  358. r: 2,
  359. sensitivity: 10,
  360. focus: {
  361. expand: {
  362. enabled: true,
  363. r: 8
  364. }
  365. }
  366. }
  367. }
  368. })
  369. beforeEach(function() {
  370. clickedData = []
  371. })
  372. it('shows tooltip with only hovered data', () => {
  373. moveMouse(1, 1)
  374. expect(
  375. (document.querySelector('.c3-tooltip-container') as any).style.display
  376. ).toEqual('none')
  377. moveMouse(48, 184)
  378. expect(
  379. (document.querySelector('.c3-tooltip-container') as any).style.display
  380. ).toEqual('block')
  381. const tooltipData = [
  382. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  383. ]
  384. expect(tooltipData.length).toBe(2) // header + data3
  385. expect(tooltipData[1].querySelector('.name').textContent).toBe('data3')
  386. expect(tooltipData[1].querySelector('.value').textContent).toBe('230')
  387. })
  388. it('expands only hovered point', () => {
  389. moveMouse(1, 1)
  390. const circleList = d3.selectAll('.c3-circle')
  391. expect(circleList.size()).toBeGreaterThan(0)
  392. // nothing expanded
  393. circleList.each(function() {
  394. expect((this as any).classList.contains('_expanded_')).toBeFalsy()
  395. })
  396. moveMouse(45, 233)
  397. circleList.each(function() {
  398. expect((this as any).classList.contains('_expanded_')).toEqual(
  399. (this as any).classList.contains('c3-circle-0') &&
  400. (this as any).parentElement.classList.contains('c3-circles-data2')
  401. )
  402. })
  403. })
  404. it('shows cursor:pointer only if hovering point', () => {
  405. const eventRect = d3.select('.c3-event-rect')
  406. moveMouse(1, 1)
  407. expect(eventRect.style('cursor')).toEqual('auto')
  408. moveMouse(49, 219)
  409. expect(eventRect.style('cursor')).toEqual('pointer')
  410. moveMouse(1, 1)
  411. expect(eventRect.style('cursor')).toEqual('auto')
  412. })
  413. it('clicks only on hovered point', () => {
  414. clickMouse(144, 201)
  415. expect(clickedData).toEqual([
  416. {
  417. x: 1,
  418. index: 1,
  419. value: 200,
  420. id: 'data1',
  421. name: 'data1'
  422. }
  423. ])
  424. })
  425. describe('with selection enabled', () => {
  426. beforeAll(() => {
  427. args.data.selection = {
  428. enabled: true,
  429. isselectable: function(d) {
  430. return d.id !== 'data3'
  431. }
  432. }
  433. })
  434. it('can toggle selection', () => {
  435. expect(d3.selectAll('.c3-circle _selected_').size()).toEqual(0)
  436. clickMouse(144, 201) // index 1 @ data1
  437. expect(d3.selectAll('.c3-circle._selected_').size()).toEqual(1)
  438. expect(
  439. d3.select('.c3-circles-data1 .c3-circle-1._selected_').size()
  440. ).toEqual(1)
  441. // data3 is not selectable
  442. clickMouse(391, 283) // index 3 @ data3
  443. expect(d3.selectAll('.c3-circle._selected_').size()).toEqual(1)
  444. expect(
  445. d3.select('.c3-circles-data3 .c3-circle-3._selected_').size()
  446. ).toEqual(0)
  447. expect(
  448. d3.select('.c3-circles-data1 .c3-circle-1._selected_').size()
  449. ).toEqual(1)
  450. clickMouse(343, 204) // index 3 @ data2
  451. expect(d3.selectAll('.c3-circle._selected_').size()).toEqual(2)
  452. expect(
  453. d3.select('.c3-circles-data2 .c3-circle-3._selected_').size()
  454. ).toEqual(1)
  455. expect(
  456. d3.select('.c3-circles-data1 .c3-circle-1._selected_').size()
  457. ).toEqual(1)
  458. clickMouse(144, 201) // index 1 @ data1
  459. expect(d3.selectAll('.c3-circle._selected_').size()).toEqual(1)
  460. expect(
  461. d3.select('.c3-circles-data2 .c3-circle-3._selected_').size()
  462. ).toEqual(1)
  463. })
  464. })
  465. describe('with tooltip_horizontal=true', () => {
  466. beforeAll(() => {
  467. args.tooltip.horizontal = true
  468. })
  469. it('can clicks on points', () => {
  470. // out of point sensitivity
  471. clickMouse(146, 46)
  472. clickMouse(343, 263)
  473. // click 3 data point
  474. clickMouse(147, 370)
  475. clickMouse(340, 203)
  476. clickMouse(537, 386)
  477. expect(clickedData).toEqual([
  478. {
  479. x: 1,
  480. value: -200,
  481. id: 'data3',
  482. index: 1,
  483. name: 'data3'
  484. },
  485. {
  486. x: 3,
  487. value: 200,
  488. id: 'data2',
  489. index: 3,
  490. name: 'data2'
  491. },
  492. {
  493. x: 5,
  494. value: -250,
  495. id: 'data1',
  496. index: 5,
  497. name: 'data1'
  498. }
  499. ])
  500. })
  501. it('shows tooltip with only closest data', () => {
  502. moveMouse(1, 1)
  503. expect(
  504. (document.querySelector('.c3-tooltip-container') as any).style
  505. .display
  506. ).toEqual('none')
  507. moveMouse(146, 46)
  508. expect(
  509. (document.querySelector('.c3-tooltip-container') as any).style
  510. .display
  511. ).toEqual('block')
  512. let tooltipData = [
  513. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  514. ]
  515. expect(tooltipData.length).toBe(2) // header + data1
  516. expect(tooltipData[1].querySelector('.name').textContent).toBe(
  517. 'data1'
  518. )
  519. expect(tooltipData[1].querySelector('.value').textContent).toBe('200')
  520. moveMouse(343, 263)
  521. expect(
  522. (document.querySelector('.c3-tooltip-container') as any).style
  523. .display
  524. ).toEqual('block')
  525. tooltipData = [
  526. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  527. ]
  528. expect(tooltipData.length).toBe(2) // header + data3
  529. expect(tooltipData[1].querySelector('.name').textContent).toBe(
  530. 'data3'
  531. )
  532. expect(tooltipData[1].querySelector('.value').textContent).toBe('0')
  533. })
  534. })
  535. })
  536. describe('tooltip_grouped=true', function() {
  537. let clickedData = []
  538. beforeAll(() => {
  539. args = {
  540. data: {
  541. columns: [
  542. ['data1', 30, 200, 200, 400, 150, -250],
  543. ['data2', 130, -100, 100, 200, 150, 50],
  544. ['data3', 230, -200, 200, 0, 250, 250]
  545. ],
  546. type: 'line',
  547. groups: [['data1', 'data2']],
  548. onclick: function(d) {
  549. clickedData.push(d)
  550. }
  551. },
  552. tooltip: {
  553. grouped: true
  554. },
  555. axis: {
  556. x: {
  557. type: 'category'
  558. }
  559. },
  560. interaction: {
  561. enabled: true
  562. },
  563. point: {
  564. r: 2,
  565. sensitivity: 10,
  566. focus: {
  567. expand: {
  568. enabled: true,
  569. r: 8
  570. }
  571. }
  572. }
  573. }
  574. })
  575. beforeEach(function() {
  576. clickedData = []
  577. })
  578. describe('with tooltip_horizontal=true', () => {
  579. beforeAll(() => {
  580. args.tooltip.horizontal = true
  581. })
  582. it('can clicks on points', () => {
  583. // out of point sensitivity
  584. clickMouse(146, 46)
  585. clickMouse(343, 263)
  586. // click 3 data point
  587. clickMouse(147, 370)
  588. clickMouse(340, 203)
  589. clickMouse(537, 386)
  590. expect(clickedData).toEqual([
  591. {
  592. x: 1,
  593. value: -200,
  594. id: 'data3',
  595. index: 1,
  596. name: 'data3'
  597. },
  598. {
  599. x: 3,
  600. value: 200,
  601. id: 'data2',
  602. index: 3,
  603. name: 'data2'
  604. },
  605. {
  606. x: 5,
  607. value: -250,
  608. id: 'data1',
  609. index: 5,
  610. name: 'data1'
  611. }
  612. ])
  613. })
  614. it('shows tooltip with all data', () => {
  615. moveMouse(1, 1)
  616. expect(
  617. (document.querySelector('.c3-tooltip-container') as any).style
  618. .display
  619. ).toEqual('block')
  620. let tooltipData = [
  621. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  622. ]
  623. expect(tooltipData.length).toBe(4) // header + data[123]
  624. expect(tooltipData[1].querySelector('.name').textContent).toBe(
  625. 'data1'
  626. )
  627. expect(tooltipData[1].querySelector('.value').textContent).toBe('30')
  628. expect(tooltipData[2].querySelector('.name').textContent).toBe(
  629. 'data3'
  630. )
  631. expect(tooltipData[2].querySelector('.value').textContent).toBe('230')
  632. expect(tooltipData[3].querySelector('.name').textContent).toBe(
  633. 'data2'
  634. )
  635. expect(tooltipData[3].querySelector('.value').textContent).toBe('130')
  636. moveMouse(146, 46)
  637. expect(
  638. (document.querySelector('.c3-tooltip-container') as any).style
  639. .display
  640. ).toEqual('block')
  641. tooltipData = [
  642. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  643. ]
  644. expect(tooltipData.length).toBe(4) // header + data[123]
  645. expect(tooltipData[1].querySelector('.name').textContent).toBe(
  646. 'data1'
  647. )
  648. expect(tooltipData[1].querySelector('.value').textContent).toBe('200')
  649. expect(tooltipData[2].querySelector('.name').textContent).toBe(
  650. 'data3'
  651. )
  652. expect(tooltipData[2].querySelector('.value').textContent).toBe(
  653. '-200'
  654. )
  655. expect(tooltipData[3].querySelector('.name').textContent).toBe(
  656. 'data2'
  657. )
  658. expect(tooltipData[3].querySelector('.value').textContent).toBe(
  659. '-100'
  660. )
  661. })
  662. })
  663. })
  664. })
  665. describe('line chart (multiple xs)', function() {
  666. let clickedData = []
  667. beforeAll(() => {
  668. args = {
  669. data: {
  670. xs: {
  671. data1: 'x1',
  672. data2: 'x2'
  673. },
  674. columns: [
  675. ['x1', 10, 30, 45, 50, 70, 100],
  676. ['x2', 30, 50, 75, 100, 120],
  677. ['data1', 30, 200, 100, 400, 150, 250],
  678. ['data2', 20, 180, 240, 100, 190]
  679. ],
  680. type: 'line',
  681. onclick: function(d) {
  682. clickedData.push(d)
  683. }
  684. },
  685. tooltip: {
  686. grouped: true,
  687. horizontal: true
  688. },
  689. interaction: {
  690. enabled: true
  691. }
  692. }
  693. })
  694. beforeEach(function() {
  695. clickedData = []
  696. })
  697. it('shows tooltip with all data', () => {
  698. moveMouse(1, 1)
  699. expect(
  700. (document.querySelector('.c3-tooltip-container') as any).style.display
  701. ).toEqual('block')
  702. let tooltipData = [
  703. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  704. ]
  705. expect(tooltipData.length).toBe(2) // header + data[1]
  706. expect(tooltipData[1].querySelector('.name').textContent).toBe('data1')
  707. expect(tooltipData[1].querySelector('.value').textContent).toBe('30')
  708. moveMouse(107, 95)
  709. expect(
  710. (document.querySelector('.c3-tooltip-container') as any).style.display
  711. ).toEqual('block')
  712. tooltipData = [...(document.querySelectorAll('.c3-tooltip tr') as any)]
  713. expect(tooltipData.length).toBe(3) // header + data[12]
  714. expect(tooltipData[1].querySelector('.name').textContent).toBe('data1')
  715. expect(tooltipData[1].querySelector('.value').textContent).toBe('200')
  716. expect(tooltipData[2].querySelector('.name').textContent).toBe('data2')
  717. expect(tooltipData[2].querySelector('.value').textContent).toBe('20')
  718. moveMouse(430, 140)
  719. expect(
  720. (document.querySelector('.c3-tooltip-container') as any).style.display
  721. ).toEqual('block')
  722. tooltipData = [...(document.querySelectorAll('.c3-tooltip tr') as any)]
  723. expect(tooltipData.length).toBe(3) // header + data[12]
  724. expect(tooltipData[1].querySelector('.name').textContent).toBe('data1')
  725. expect(tooltipData[1].querySelector('.value').textContent).toBe('250')
  726. expect(tooltipData[2].querySelector('.name').textContent).toBe('data2')
  727. expect(tooltipData[2].querySelector('.value').textContent).toBe('100')
  728. })
  729. })
  730. describe('scatter chart', function() {
  731. describe('tooltip_grouped=true', function() {
  732. beforeAll(() => {
  733. args = {
  734. data: {
  735. columns: [
  736. ['data1', 30, null, 100, 400, -150, 250],
  737. ['data2', 50, 20, 10, 40, 15, 25],
  738. ['data3', -150, 120, 110, 140, 115, 125]
  739. ],
  740. type: 'scatter'
  741. },
  742. tooltip: {
  743. grouped: true
  744. },
  745. interaction: {
  746. enabled: true
  747. }
  748. }
  749. })
  750. it('shows tooltip with visible data of currently hovered category', () => {
  751. moveMouse(20, 20)
  752. let tooltipData = [
  753. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  754. ]
  755. expect(tooltipData.length).toBe(4) // header + data[123]
  756. expect(tooltipData[1].querySelector('.name').textContent).toBe('data2')
  757. expect(tooltipData[1].querySelector('.value').textContent).toBe('50')
  758. expect(tooltipData[2].querySelector('.name').textContent).toBe('data1')
  759. expect(tooltipData[2].querySelector('.value').textContent).toBe('30')
  760. expect(tooltipData[3].querySelector('.name').textContent).toBe('data3')
  761. expect(tooltipData[3].querySelector('.value').textContent).toBe('-150')
  762. moveMouse(350, 354)
  763. tooltipData = [...(document.querySelectorAll('.c3-tooltip tr') as any)]
  764. expect(tooltipData.length).toBe(4) // header + data[123]
  765. expect(tooltipData[1].querySelector('.name').textContent).toBe('data1')
  766. expect(tooltipData[1].querySelector('.value').textContent).toBe('400')
  767. expect(tooltipData[2].querySelector('.name').textContent).toBe('data3')
  768. expect(tooltipData[2].querySelector('.value').textContent).toBe('140')
  769. expect(tooltipData[3].querySelector('.name').textContent).toBe('data2')
  770. expect(tooltipData[3].querySelector('.value').textContent).toBe('40')
  771. })
  772. it('shows x grid', () => {
  773. moveMouse(20, 20)
  774. expect(d3.select('.c3-xgrid-focus').style('visibility')).toBe('visible')
  775. })
  776. })
  777. })
  778. describe('area chart (timeseries)', function() {
  779. describe('tooltip_grouped=true', function() {
  780. beforeAll(() => {
  781. args = {
  782. data: {
  783. x: 'x',
  784. columns: [
  785. [
  786. 'x',
  787. '2018-01-01',
  788. '2018-01-02',
  789. '2018-01-03',
  790. '2018-01-04',
  791. '2018-01-05',
  792. '2018-01-06'
  793. ],
  794. ['data1', 30, 200, 200, 400, 150, 250],
  795. ['data2', 130, 100, 100, 200, 150, 50],
  796. ['data3', 230, 200, 200, 0, 250, 250]
  797. ],
  798. type: 'area',
  799. groups: [['data1', 'data2', 'data3']]
  800. },
  801. tooltip: {
  802. grouped: true
  803. },
  804. axis: {
  805. x: {
  806. type: 'timeseries'
  807. }
  808. },
  809. interaction: {
  810. enabled: true
  811. }
  812. }
  813. })
  814. it('shows tooltip with visible data of currently hovered category', () => {
  815. moveMouse(20, 20)
  816. expect(
  817. (document.querySelector('.c3-tooltip-container') as any).style.display
  818. ).toEqual('block')
  819. const tooltipData = [
  820. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  821. ]
  822. expect(tooltipData.length).toBe(4) // header + data[123]
  823. expect(tooltipData[1].querySelector('.name').textContent).toBe('data1')
  824. expect(tooltipData[2].querySelector('.name').textContent).toBe('data3')
  825. expect(tooltipData[3].querySelector('.name').textContent).toBe('data2')
  826. })
  827. it('shows cursor:pointer only if hovering area', () => {
  828. const eventRect = d3.select('.c3-event-rect')
  829. moveMouse(1, 1)
  830. expect(eventRect.style('cursor')).toEqual('auto')
  831. moveMouse(360, 48)
  832. expect(eventRect.style('cursor')).toEqual('pointer')
  833. moveMouse(1, 1)
  834. expect(eventRect.style('cursor')).toEqual('auto')
  835. })
  836. })
  837. describe('tooltip_grouped=false', function() {
  838. beforeAll(() => {
  839. args = {
  840. data: {
  841. x: 'x',
  842. columns: [
  843. [
  844. 'x',
  845. '2018-01-01',
  846. '2018-01-02',
  847. '2018-01-03',
  848. '2018-01-04',
  849. '2018-01-05',
  850. '2018-01-06'
  851. ],
  852. ['data1', 30, 200, 200, 400, 150, 250],
  853. ['data2', 130, 100, 100, 200, 150, 50],
  854. ['data3', 230, 200, 200, 0, 250, 250]
  855. ],
  856. type: 'area',
  857. groups: [['data1', 'data2', 'data3']]
  858. },
  859. tooltip: {
  860. grouped: false
  861. },
  862. axis: {
  863. x: {
  864. type: 'timeseries'
  865. },
  866. rotated: false
  867. },
  868. interaction: {
  869. enabled: true
  870. }
  871. }
  872. })
  873. it('shows tooltip with only hovered data', () => {
  874. moveMouse(1, 1)
  875. expect(
  876. (document.querySelector('.c3-tooltip-container') as any).style.display
  877. ).toEqual('none')
  878. moveMouse(5, 174)
  879. expect(
  880. (document.querySelector('.c3-tooltip-container') as any).style.display
  881. ).toEqual('block')
  882. const tooltipData = [
  883. ...(document.querySelectorAll('.c3-tooltip tr') as any)
  884. ]
  885. expect(tooltipData.length).toBe(2) // header + data1
  886. expect(tooltipData[1].querySelector('.name').textContent).toBe('data1')
  887. expect(tooltipData[1].querySelector('.value').textContent).toBe('30')
  888. })
  889. })
  890. })
  891. describe('disabled', function() {
  892. beforeAll(() => {
  893. args = {
  894. data: {
  895. columns: [
  896. ['data1', 30, 200, 200, 400, 150, -250],
  897. ['data2', 130, -100, 100, 200, 150, 50],
  898. ['data3', 230, -200, 200, 0, 250, 250]
  899. ],
  900. type: 'bar',
  901. groups: [['data1', 'data2']]
  902. },
  903. axis: {
  904. x: {
  905. type: 'category'
  906. }
  907. },
  908. interaction: {
  909. enabled: false
  910. }
  911. }
  912. })
  913. it('generate a single rect', () => {
  914. const eventRectList = d3.selectAll('.c3-event-rect')
  915. expect(eventRectList.size()).toBe(1)
  916. expect(eventRectList.attr('x')).toEqual('0')
  917. expect(eventRectList.attr('y')).toEqual('0')
  918. expect(eventRectList.attr('height')).toEqual('' + chart.internal.height)
  919. expect(eventRectList.attr('width')).toEqual('' + chart.internal.width)
  920. })
  921. it('does not show tooltip when hovering data', () => {
  922. moveMouse(40, 260)
  923. expect(
  924. (document.querySelector('.c3-tooltip-container') as any).style.display
  925. ).toEqual('none')
  926. })
  927. it('does not show cursor:pointer when hovering data', () => {
  928. moveMouse(40, 260)
  929. expect(d3.select('.c3-event-rect').style('cursor')).toEqual('auto')
  930. })
  931. })
  932. })