core.tooltip.tests.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. // Test the rectangle element
  2. describe('Core.Tooltip', function() {
  3. describe('config', function() {
  4. it('should not include the dataset label in the body string if not defined', function() {
  5. var data = {
  6. datasets: [{
  7. data: [10, 20, 30],
  8. pointHoverBorderColor: 'rgb(255, 0, 0)',
  9. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  10. }],
  11. labels: ['Point 1', 'Point 2', 'Point 3']
  12. };
  13. var tooltipItem = {
  14. index: 1,
  15. datasetIndex: 0,
  16. xLabel: 'Point 2',
  17. yLabel: '20'
  18. };
  19. var label = Chart.defaults.global.tooltips.callbacks.label(tooltipItem, data);
  20. expect(label).toBe('20');
  21. data.datasets[0].label = 'My dataset';
  22. label = Chart.defaults.global.tooltips.callbacks.label(tooltipItem, data);
  23. expect(label).toBe('My dataset: 20');
  24. });
  25. });
  26. describe('index mode', function() {
  27. it('Should only use x distance when intersect is false', function() {
  28. var chart = window.acquireChart({
  29. type: 'line',
  30. data: {
  31. datasets: [{
  32. label: 'Dataset 1',
  33. data: [10, 20, 30],
  34. pointHoverBorderColor: 'rgb(255, 0, 0)',
  35. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  36. }, {
  37. label: 'Dataset 2',
  38. data: [40, 40, 40],
  39. pointHoverBorderColor: 'rgb(0, 0, 255)',
  40. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  41. }],
  42. labels: ['Point 1', 'Point 2', 'Point 3']
  43. },
  44. options: {
  45. tooltips: {
  46. mode: 'index',
  47. intersect: false,
  48. },
  49. hover: {
  50. mode: 'index',
  51. intersect: false
  52. }
  53. }
  54. });
  55. // Trigger an event over top of the
  56. var meta = chart.getDatasetMeta(0);
  57. var point = meta.data[1];
  58. var node = chart.canvas;
  59. var rect = node.getBoundingClientRect();
  60. var evt = new MouseEvent('mousemove', {
  61. view: window,
  62. bubbles: true,
  63. cancelable: true,
  64. clientX: rect.left + point._model.x,
  65. clientY: 0
  66. });
  67. // Manually trigger rather than having an async test
  68. node.dispatchEvent(evt);
  69. // Check and see if tooltip was displayed
  70. var tooltip = chart.tooltip;
  71. var globalDefaults = Chart.defaults.global;
  72. expect(tooltip._view).toEqual(jasmine.objectContaining({
  73. // Positioning
  74. xPadding: 6,
  75. yPadding: 6,
  76. xAlign: 'left',
  77. yAlign: 'center',
  78. // Body
  79. bodyFontColor: '#fff',
  80. _bodyFontFamily: globalDefaults.defaultFontFamily,
  81. _bodyFontStyle: globalDefaults.defaultFontStyle,
  82. _bodyAlign: 'left',
  83. bodyFontSize: globalDefaults.defaultFontSize,
  84. bodySpacing: 2,
  85. // Title
  86. titleFontColor: '#fff',
  87. _titleFontFamily: globalDefaults.defaultFontFamily,
  88. _titleFontStyle: 'bold',
  89. titleFontSize: globalDefaults.defaultFontSize,
  90. _titleAlign: 'left',
  91. titleSpacing: 2,
  92. titleMarginBottom: 6,
  93. // Footer
  94. footerFontColor: '#fff',
  95. _footerFontFamily: globalDefaults.defaultFontFamily,
  96. _footerFontStyle: 'bold',
  97. footerFontSize: globalDefaults.defaultFontSize,
  98. _footerAlign: 'left',
  99. footerSpacing: 2,
  100. footerMarginTop: 6,
  101. // Appearance
  102. caretSize: 5,
  103. cornerRadius: 6,
  104. backgroundColor: 'rgba(0,0,0,0.8)',
  105. opacity: 1,
  106. legendColorBackground: '#fff',
  107. displayColors: true,
  108. // Text
  109. title: ['Point 2'],
  110. beforeBody: [],
  111. body: [{
  112. before: [],
  113. lines: ['Dataset 1: 20'],
  114. after: []
  115. }, {
  116. before: [],
  117. lines: ['Dataset 2: 40'],
  118. after: []
  119. }],
  120. afterBody: [],
  121. footer: [],
  122. caretPadding: 2,
  123. labelColors: [{
  124. borderColor: 'rgb(255, 0, 0)',
  125. backgroundColor: 'rgb(0, 255, 0)'
  126. }, {
  127. borderColor: 'rgb(0, 0, 255)',
  128. backgroundColor: 'rgb(0, 255, 255)'
  129. }]
  130. }));
  131. expect(tooltip._view.x).toBeCloseToPixel(266);
  132. expect(tooltip._view.y).toBeCloseToPixel(155);
  133. });
  134. it('Should only display if intersecting if intersect is set', function() {
  135. var chart = window.acquireChart({
  136. type: 'line',
  137. data: {
  138. datasets: [{
  139. label: 'Dataset 1',
  140. data: [10, 20, 30],
  141. pointHoverBorderColor: 'rgb(255, 0, 0)',
  142. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  143. }, {
  144. label: 'Dataset 2',
  145. data: [40, 40, 40],
  146. pointHoverBorderColor: 'rgb(0, 0, 255)',
  147. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  148. }],
  149. labels: ['Point 1', 'Point 2', 'Point 3']
  150. },
  151. options: {
  152. tooltips: {
  153. mode: 'index',
  154. intersect: true
  155. }
  156. }
  157. });
  158. // Trigger an event over top of the
  159. var meta = chart.getDatasetMeta(0);
  160. var point = meta.data[1];
  161. var node = chart.canvas;
  162. var rect = node.getBoundingClientRect();
  163. var evt = new MouseEvent('mousemove', {
  164. view: window,
  165. bubbles: true,
  166. cancelable: true,
  167. clientX: rect.left + point._model.x,
  168. clientY: 0
  169. });
  170. // Manually trigger rather than having an async test
  171. node.dispatchEvent(evt);
  172. // Check and see if tooltip was displayed
  173. var tooltip = chart.tooltip;
  174. var globalDefaults = Chart.defaults.global;
  175. expect(tooltip._view).toEqual(jasmine.objectContaining({
  176. // Positioning
  177. xPadding: 6,
  178. yPadding: 6,
  179. // Body
  180. bodyFontColor: '#fff',
  181. _bodyFontFamily: globalDefaults.defaultFontFamily,
  182. _bodyFontStyle: globalDefaults.defaultFontStyle,
  183. _bodyAlign: 'left',
  184. bodyFontSize: globalDefaults.defaultFontSize,
  185. bodySpacing: 2,
  186. // Title
  187. titleFontColor: '#fff',
  188. _titleFontFamily: globalDefaults.defaultFontFamily,
  189. _titleFontStyle: 'bold',
  190. titleFontSize: globalDefaults.defaultFontSize,
  191. _titleAlign: 'left',
  192. titleSpacing: 2,
  193. titleMarginBottom: 6,
  194. // Footer
  195. footerFontColor: '#fff',
  196. _footerFontFamily: globalDefaults.defaultFontFamily,
  197. _footerFontStyle: 'bold',
  198. footerFontSize: globalDefaults.defaultFontSize,
  199. _footerAlign: 'left',
  200. footerSpacing: 2,
  201. footerMarginTop: 6,
  202. // Appearance
  203. caretSize: 5,
  204. cornerRadius: 6,
  205. backgroundColor: 'rgba(0,0,0,0.8)',
  206. opacity: 0,
  207. legendColorBackground: '#fff',
  208. displayColors: true,
  209. }));
  210. });
  211. });
  212. it('Should display in single mode', function() {
  213. var chart = window.acquireChart({
  214. type: 'line',
  215. data: {
  216. datasets: [{
  217. label: 'Dataset 1',
  218. data: [10, 20, 30],
  219. pointHoverBorderColor: 'rgb(255, 0, 0)',
  220. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  221. }, {
  222. label: 'Dataset 2',
  223. data: [40, 40, 40],
  224. pointHoverBorderColor: 'rgb(0, 0, 255)',
  225. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  226. }],
  227. labels: ['Point 1', 'Point 2', 'Point 3']
  228. },
  229. options: {
  230. tooltips: {
  231. mode: 'single'
  232. }
  233. }
  234. });
  235. // Trigger an event over top of the
  236. var meta = chart.getDatasetMeta(0);
  237. var point = meta.data[1];
  238. var node = chart.canvas;
  239. var rect = node.getBoundingClientRect();
  240. var evt = new MouseEvent('mousemove', {
  241. view: window,
  242. bubbles: true,
  243. cancelable: true,
  244. clientX: rect.left + point._model.x,
  245. clientY: rect.top + point._model.y
  246. });
  247. // Manually trigger rather than having an async test
  248. node.dispatchEvent(evt);
  249. // Check and see if tooltip was displayed
  250. var tooltip = chart.tooltip;
  251. var globalDefaults = Chart.defaults.global;
  252. expect(tooltip._view).toEqual(jasmine.objectContaining({
  253. // Positioning
  254. xPadding: 6,
  255. yPadding: 6,
  256. xAlign: 'left',
  257. yAlign: 'center',
  258. // Body
  259. bodyFontColor: '#fff',
  260. _bodyFontFamily: globalDefaults.defaultFontFamily,
  261. _bodyFontStyle: globalDefaults.defaultFontStyle,
  262. _bodyAlign: 'left',
  263. bodyFontSize: globalDefaults.defaultFontSize,
  264. bodySpacing: 2,
  265. // Title
  266. titleFontColor: '#fff',
  267. _titleFontFamily: globalDefaults.defaultFontFamily,
  268. _titleFontStyle: 'bold',
  269. titleFontSize: globalDefaults.defaultFontSize,
  270. _titleAlign: 'left',
  271. titleSpacing: 2,
  272. titleMarginBottom: 6,
  273. // Footer
  274. footerFontColor: '#fff',
  275. _footerFontFamily: globalDefaults.defaultFontFamily,
  276. _footerFontStyle: 'bold',
  277. footerFontSize: globalDefaults.defaultFontSize,
  278. _footerAlign: 'left',
  279. footerSpacing: 2,
  280. footerMarginTop: 6,
  281. // Appearance
  282. caretSize: 5,
  283. cornerRadius: 6,
  284. backgroundColor: 'rgba(0,0,0,0.8)',
  285. opacity: 1,
  286. legendColorBackground: '#fff',
  287. displayColors: true,
  288. // Text
  289. title: ['Point 2'],
  290. beforeBody: [],
  291. body: [{
  292. before: [],
  293. lines: ['Dataset 1: 20'],
  294. after: []
  295. }],
  296. afterBody: [],
  297. footer: [],
  298. caretPadding: 2,
  299. labelTextColors: ['#fff'],
  300. labelColors: [{
  301. borderColor: 'rgb(255, 0, 0)',
  302. backgroundColor: 'rgb(0, 255, 0)'
  303. }]
  304. }));
  305. expect(tooltip._view.x).toBeCloseToPixel(266);
  306. expect(tooltip._view.y).toBeCloseToPixel(312);
  307. });
  308. it('Should display information from user callbacks', function() {
  309. var chart = window.acquireChart({
  310. type: 'line',
  311. data: {
  312. datasets: [{
  313. label: 'Dataset 1',
  314. data: [10, 20, 30],
  315. pointHoverBorderColor: 'rgb(255, 0, 0)',
  316. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  317. }, {
  318. label: 'Dataset 2',
  319. data: [40, 40, 40],
  320. pointHoverBorderColor: 'rgb(0, 0, 255)',
  321. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  322. }],
  323. labels: ['Point 1', 'Point 2', 'Point 3']
  324. },
  325. options: {
  326. tooltips: {
  327. mode: 'label',
  328. callbacks: {
  329. beforeTitle: function() {
  330. return 'beforeTitle';
  331. },
  332. title: function() {
  333. return 'title';
  334. },
  335. afterTitle: function() {
  336. return 'afterTitle';
  337. },
  338. beforeBody: function() {
  339. return 'beforeBody';
  340. },
  341. beforeLabel: function() {
  342. return 'beforeLabel';
  343. },
  344. label: function() {
  345. return 'label';
  346. },
  347. afterLabel: function() {
  348. return 'afterLabel';
  349. },
  350. afterBody: function() {
  351. return 'afterBody';
  352. },
  353. beforeFooter: function() {
  354. return 'beforeFooter';
  355. },
  356. footer: function() {
  357. return 'footer';
  358. },
  359. afterFooter: function() {
  360. return 'afterFooter';
  361. },
  362. labelTextColor: function() {
  363. return 'labelTextColor';
  364. }
  365. }
  366. }
  367. }
  368. });
  369. // Trigger an event over top of the
  370. var meta = chart.getDatasetMeta(0);
  371. var point = meta.data[1];
  372. var node = chart.canvas;
  373. var rect = node.getBoundingClientRect();
  374. var evt = new MouseEvent('mousemove', {
  375. view: window,
  376. bubbles: true,
  377. cancelable: true,
  378. clientX: rect.left + point._model.x,
  379. clientY: rect.top + point._model.y
  380. });
  381. // Manually trigger rather than having an async test
  382. node.dispatchEvent(evt);
  383. // Check and see if tooltip was displayed
  384. var tooltip = chart.tooltip;
  385. var globalDefaults = Chart.defaults.global;
  386. expect(tooltip._view).toEqual(jasmine.objectContaining({
  387. // Positioning
  388. xPadding: 6,
  389. yPadding: 6,
  390. xAlign: 'center',
  391. yAlign: 'top',
  392. // Body
  393. bodyFontColor: '#fff',
  394. _bodyFontFamily: globalDefaults.defaultFontFamily,
  395. _bodyFontStyle: globalDefaults.defaultFontStyle,
  396. _bodyAlign: 'left',
  397. bodyFontSize: globalDefaults.defaultFontSize,
  398. bodySpacing: 2,
  399. // Title
  400. titleFontColor: '#fff',
  401. _titleFontFamily: globalDefaults.defaultFontFamily,
  402. _titleFontStyle: 'bold',
  403. titleFontSize: globalDefaults.defaultFontSize,
  404. _titleAlign: 'left',
  405. titleSpacing: 2,
  406. titleMarginBottom: 6,
  407. // Footer
  408. footerFontColor: '#fff',
  409. _footerFontFamily: globalDefaults.defaultFontFamily,
  410. _footerFontStyle: 'bold',
  411. footerFontSize: globalDefaults.defaultFontSize,
  412. _footerAlign: 'left',
  413. footerSpacing: 2,
  414. footerMarginTop: 6,
  415. // Appearance
  416. caretSize: 5,
  417. cornerRadius: 6,
  418. backgroundColor: 'rgba(0,0,0,0.8)',
  419. opacity: 1,
  420. legendColorBackground: '#fff',
  421. // Text
  422. title: ['beforeTitle', 'title', 'afterTitle'],
  423. beforeBody: ['beforeBody'],
  424. body: [{
  425. before: ['beforeLabel'],
  426. lines: ['label'],
  427. after: ['afterLabel']
  428. }, {
  429. before: ['beforeLabel'],
  430. lines: ['label'],
  431. after: ['afterLabel']
  432. }],
  433. afterBody: ['afterBody'],
  434. footer: ['beforeFooter', 'footer', 'afterFooter'],
  435. caretPadding: 2,
  436. labelTextColors: ['labelTextColor', 'labelTextColor'],
  437. labelColors: [{
  438. borderColor: 'rgb(255, 0, 0)',
  439. backgroundColor: 'rgb(0, 255, 0)'
  440. }, {
  441. borderColor: 'rgb(0, 0, 255)',
  442. backgroundColor: 'rgb(0, 255, 255)'
  443. }]
  444. }));
  445. expect(tooltip._view.x).toBeCloseToPixel(214);
  446. expect(tooltip._view.y).toBeCloseToPixel(190);
  447. });
  448. it('Should allow sorting items', function() {
  449. var chart = window.acquireChart({
  450. type: 'line',
  451. data: {
  452. datasets: [{
  453. label: 'Dataset 1',
  454. data: [10, 20, 30],
  455. pointHoverBorderColor: 'rgb(255, 0, 0)',
  456. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  457. }, {
  458. label: 'Dataset 2',
  459. data: [40, 40, 40],
  460. pointHoverBorderColor: 'rgb(0, 0, 255)',
  461. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  462. }],
  463. labels: ['Point 1', 'Point 2', 'Point 3']
  464. },
  465. options: {
  466. tooltips: {
  467. mode: 'label',
  468. itemSort: function(a, b) {
  469. return a.datasetIndex > b.datasetIndex ? -1 : 1;
  470. }
  471. }
  472. }
  473. });
  474. // Trigger an event over top of the
  475. var meta0 = chart.getDatasetMeta(0);
  476. var point0 = meta0.data[1];
  477. var node = chart.canvas;
  478. var rect = node.getBoundingClientRect();
  479. var evt = new MouseEvent('mousemove', {
  480. view: window,
  481. bubbles: true,
  482. cancelable: true,
  483. clientX: rect.left + point0._model.x,
  484. clientY: rect.top + point0._model.y
  485. });
  486. // Manually trigger rather than having an async test
  487. node.dispatchEvent(evt);
  488. // Check and see if tooltip was displayed
  489. var tooltip = chart.tooltip;
  490. expect(tooltip._view).toEqual(jasmine.objectContaining({
  491. // Positioning
  492. xAlign: 'left',
  493. yAlign: 'center',
  494. // Text
  495. title: ['Point 2'],
  496. beforeBody: [],
  497. body: [{
  498. before: [],
  499. lines: ['Dataset 2: 40'],
  500. after: []
  501. }, {
  502. before: [],
  503. lines: ['Dataset 1: 20'],
  504. after: []
  505. }],
  506. afterBody: [],
  507. footer: [],
  508. labelColors: [{
  509. borderColor: 'rgb(0, 0, 255)',
  510. backgroundColor: 'rgb(0, 255, 255)'
  511. }, {
  512. borderColor: 'rgb(255, 0, 0)',
  513. backgroundColor: 'rgb(0, 255, 0)'
  514. }]
  515. }));
  516. expect(tooltip._view.x).toBeCloseToPixel(266);
  517. expect(tooltip._view.y).toBeCloseToPixel(155);
  518. });
  519. it('should filter items from the tooltip using the callback', function() {
  520. var chart = window.acquireChart({
  521. type: 'line',
  522. data: {
  523. datasets: [{
  524. label: 'Dataset 1',
  525. data: [10, 20, 30],
  526. pointHoverBorderColor: 'rgb(255, 0, 0)',
  527. pointHoverBackgroundColor: 'rgb(0, 255, 0)',
  528. tooltipHidden: true
  529. }, {
  530. label: 'Dataset 2',
  531. data: [40, 40, 40],
  532. pointHoverBorderColor: 'rgb(0, 0, 255)',
  533. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  534. }],
  535. labels: ['Point 1', 'Point 2', 'Point 3']
  536. },
  537. options: {
  538. tooltips: {
  539. mode: 'label',
  540. filter: function(tooltipItem, data) {
  541. // For testing purposes remove the first dataset that has a tooltipHidden property
  542. return !data.datasets[tooltipItem.datasetIndex].tooltipHidden;
  543. }
  544. }
  545. }
  546. });
  547. // Trigger an event over top of the
  548. var meta0 = chart.getDatasetMeta(0);
  549. var point0 = meta0.data[1];
  550. var node = chart.canvas;
  551. var rect = node.getBoundingClientRect();
  552. var evt = new MouseEvent('mousemove', {
  553. view: window,
  554. bubbles: true,
  555. cancelable: true,
  556. clientX: rect.left + point0._model.x,
  557. clientY: rect.top + point0._model.y
  558. });
  559. // Manually trigger rather than having an async test
  560. node.dispatchEvent(evt);
  561. // Check and see if tooltip was displayed
  562. var tooltip = chart.tooltip;
  563. expect(tooltip._view).toEqual(jasmine.objectContaining({
  564. // Positioning
  565. xAlign: 'left',
  566. yAlign: 'center',
  567. // Text
  568. title: ['Point 2'],
  569. beforeBody: [],
  570. body: [{
  571. before: [],
  572. lines: ['Dataset 2: 40'],
  573. after: []
  574. }],
  575. afterBody: [],
  576. footer: [],
  577. labelColors: [{
  578. borderColor: 'rgb(0, 0, 255)',
  579. backgroundColor: 'rgb(0, 255, 255)'
  580. }]
  581. }));
  582. });
  583. it('should set the caretPadding based on a config setting', function() {
  584. var chart = window.acquireChart({
  585. type: 'line',
  586. data: {
  587. datasets: [{
  588. label: 'Dataset 1',
  589. data: [10, 20, 30],
  590. pointHoverBorderColor: 'rgb(255, 0, 0)',
  591. pointHoverBackgroundColor: 'rgb(0, 255, 0)',
  592. tooltipHidden: true
  593. }, {
  594. label: 'Dataset 2',
  595. data: [40, 40, 40],
  596. pointHoverBorderColor: 'rgb(0, 0, 255)',
  597. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  598. }],
  599. labels: ['Point 1', 'Point 2', 'Point 3']
  600. },
  601. options: {
  602. tooltips: {
  603. caretPadding: 10
  604. }
  605. }
  606. });
  607. // Trigger an event over top of the
  608. var meta0 = chart.getDatasetMeta(0);
  609. var point0 = meta0.data[1];
  610. var node = chart.canvas;
  611. var rect = node.getBoundingClientRect();
  612. var evt = new MouseEvent('mousemove', {
  613. view: window,
  614. bubbles: true,
  615. cancelable: true,
  616. clientX: rect.left + point0._model.x,
  617. clientY: rect.top + point0._model.y
  618. });
  619. // Manually trigger rather than having an async test
  620. node.dispatchEvent(evt);
  621. // Check and see if tooltip was displayed
  622. var tooltip = chart.tooltip;
  623. expect(tooltip._model).toEqual(jasmine.objectContaining({
  624. // Positioning
  625. caretPadding: 10,
  626. }));
  627. });
  628. it('Should have dataPoints', function() {
  629. var chart = window.acquireChart({
  630. type: 'line',
  631. data: {
  632. datasets: [{
  633. label: 'Dataset 1',
  634. data: [10, 20, 30],
  635. pointHoverBorderColor: 'rgb(255, 0, 0)',
  636. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  637. }, {
  638. label: 'Dataset 2',
  639. data: [40, 40, 40],
  640. pointHoverBorderColor: 'rgb(0, 0, 255)',
  641. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  642. }],
  643. labels: ['Point 1', 'Point 2', 'Point 3']
  644. },
  645. options: {
  646. tooltips: {
  647. mode: 'single'
  648. }
  649. }
  650. });
  651. // Trigger an event over top of the
  652. var pointIndex = 1;
  653. var datasetIndex = 0;
  654. var meta = chart.getDatasetMeta(datasetIndex);
  655. var point = meta.data[pointIndex];
  656. var node = chart.canvas;
  657. var rect = node.getBoundingClientRect();
  658. var evt = new MouseEvent('mousemove', {
  659. view: window,
  660. bubbles: true,
  661. cancelable: true,
  662. clientX: rect.left + point._model.x,
  663. clientY: rect.top + point._model.y
  664. });
  665. // Manually trigger rather than having an async test
  666. node.dispatchEvent(evt);
  667. // Check and see if tooltip was displayed
  668. var tooltip = chart.tooltip;
  669. expect(tooltip._view instanceof Object).toBe(true);
  670. expect(tooltip._view.dataPoints instanceof Array).toBe(true);
  671. expect(tooltip._view.dataPoints.length).toEqual(1);
  672. expect(tooltip._view.dataPoints[0].index).toEqual(pointIndex);
  673. expect(tooltip._view.dataPoints[0].datasetIndex).toEqual(datasetIndex);
  674. expect(tooltip._view.dataPoints[0].xLabel).toEqual(
  675. chart.data.labels[pointIndex]
  676. );
  677. expect(tooltip._view.dataPoints[0].yLabel).toEqual(
  678. chart.data.datasets[datasetIndex].data[pointIndex]
  679. );
  680. expect(tooltip._view.dataPoints[0].x).toBeCloseToPixel(point._model.x);
  681. expect(tooltip._view.dataPoints[0].y).toBeCloseToPixel(point._model.y);
  682. });
  683. it('Should not update if active element has not changed', function() {
  684. var chart = window.acquireChart({
  685. type: 'line',
  686. data: {
  687. datasets: [{
  688. label: 'Dataset 1',
  689. data: [10, 20, 30],
  690. pointHoverBorderColor: 'rgb(255, 0, 0)',
  691. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  692. }, {
  693. label: 'Dataset 2',
  694. data: [40, 40, 40],
  695. pointHoverBorderColor: 'rgb(0, 0, 255)',
  696. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  697. }],
  698. labels: ['Point 1', 'Point 2', 'Point 3']
  699. },
  700. options: {
  701. tooltips: {
  702. mode: 'single',
  703. callbacks: {
  704. title: function() {
  705. return 'registering callback...';
  706. }
  707. }
  708. }
  709. }
  710. });
  711. // Trigger an event over top of the
  712. var meta = chart.getDatasetMeta(0);
  713. var firstPoint = meta.data[1];
  714. var node = chart.chart.canvas;
  715. var rect = node.getBoundingClientRect();
  716. var firstEvent = new MouseEvent('mousemove', {
  717. view: window,
  718. bubbles: false,
  719. cancelable: true,
  720. clientX: rect.left + firstPoint._model.x,
  721. clientY: rect.top + firstPoint._model.y
  722. });
  723. var tooltip = chart.tooltip;
  724. spyOn(tooltip, 'update');
  725. /* Manually trigger rather than having an async test */
  726. // First dispatch change event, should update tooltip
  727. node.dispatchEvent(firstEvent);
  728. expect(tooltip.update).toHaveBeenCalledWith(true);
  729. // Reset calls
  730. tooltip.update.calls.reset();
  731. // Second dispatch change event (same event), should not update tooltip
  732. node.dispatchEvent(firstEvent);
  733. expect(tooltip.update).not.toHaveBeenCalled();
  734. });
  735. describe('positioners', function() {
  736. it('Should call custom positioner with correct parameters and scope', function() {
  737. Chart.Tooltip.positioners.test = function() {
  738. return {x: 0, y: 0};
  739. };
  740. spyOn(Chart.Tooltip.positioners, 'test').and.callThrough();
  741. var chart = window.acquireChart({
  742. type: 'line',
  743. data: {
  744. datasets: [{
  745. label: 'Dataset 1',
  746. data: [10, 20, 30],
  747. pointHoverBorderColor: 'rgb(255, 0, 0)',
  748. pointHoverBackgroundColor: 'rgb(0, 255, 0)'
  749. }, {
  750. label: 'Dataset 2',
  751. data: [40, 40, 40],
  752. pointHoverBorderColor: 'rgb(0, 0, 255)',
  753. pointHoverBackgroundColor: 'rgb(0, 255, 255)'
  754. }],
  755. labels: ['Point 1', 'Point 2', 'Point 3']
  756. },
  757. options: {
  758. tooltips: {
  759. mode: 'nearest',
  760. position: 'test'
  761. }
  762. }
  763. });
  764. // Trigger an event over top of the
  765. var pointIndex = 1;
  766. var datasetIndex = 0;
  767. var meta = chart.getDatasetMeta(datasetIndex);
  768. var point = meta.data[pointIndex];
  769. var node = chart.canvas;
  770. var rect = node.getBoundingClientRect();
  771. var evt = new MouseEvent('mousemove', {
  772. view: window,
  773. bubbles: true,
  774. cancelable: true,
  775. clientX: rect.left + point._model.x,
  776. clientY: rect.top + point._model.y
  777. });
  778. // Manually trigger rather than having an async test
  779. node.dispatchEvent(evt);
  780. var fn = Chart.Tooltip.positioners.test;
  781. expect(fn.calls.count()).toBe(1);
  782. expect(fn.calls.first().args[0] instanceof Array).toBe(true);
  783. expect(fn.calls.first().args[1].hasOwnProperty('x')).toBe(true);
  784. expect(fn.calls.first().args[1].hasOwnProperty('y')).toBe(true);
  785. expect(fn.calls.first().object instanceof Chart.Tooltip).toBe(true);
  786. });
  787. });
  788. it('Should avoid tooltip truncation in x axis if there is enough space to show tooltip without truncation', function() {
  789. var chart = window.acquireChart({
  790. type: 'pie',
  791. data: {
  792. datasets: [{
  793. data: [
  794. 50,
  795. 50
  796. ],
  797. backgroundColor: [
  798. 'rgb(255, 0, 0)',
  799. 'rgb(0, 255, 0)'
  800. ],
  801. label: 'Dataset 1'
  802. }],
  803. labels: [
  804. 'Red long tooltip text to avoid unnecessary loop steps',
  805. 'Green long tooltip text to avoid unnecessary loop steps'
  806. ]
  807. },
  808. options: {
  809. responsive: true,
  810. animation: {
  811. // without this slice center point is calculated wrong
  812. animateRotate: false
  813. }
  814. }
  815. });
  816. // Trigger an event over top of the slice
  817. for (var slice = 0; slice < 2; slice++) {
  818. var meta = chart.getDatasetMeta(0);
  819. var point = meta.data[slice].getCenterPoint();
  820. var tooltipPosition = meta.data[slice].tooltipPosition();
  821. var node = chart.canvas;
  822. var rect = node.getBoundingClientRect();
  823. var mouseMoveEvent = new MouseEvent('mousemove', {
  824. view: window,
  825. bubbles: true,
  826. cancelable: true,
  827. clientX: rect.left + point.x,
  828. clientY: rect.top + point.y
  829. });
  830. var mouseOutEvent = new MouseEvent('mouseout');
  831. // Lets cycle while tooltip is narrower than chart area
  832. var infiniteCycleDefense = 70;
  833. for (var i = 0; i < infiniteCycleDefense; i++) {
  834. chart.config.data.labels[slice] = chart.config.data.labels[slice] + 'l';
  835. chart.update();
  836. node.dispatchEvent(mouseOutEvent);
  837. node.dispatchEvent(mouseMoveEvent);
  838. var model = chart.tooltip._model;
  839. expect(model.x).toBeGreaterThanOrEqual(0);
  840. if (model.width <= chart.width) {
  841. expect(model.x + model.width).toBeLessThanOrEqual(chart.width);
  842. }
  843. expect(model.caretX).toBe(tooltipPosition.x);
  844. // if tooltip is longer than chart area then all tests done
  845. if (model.width > chart.width) {
  846. break;
  847. }
  848. }
  849. }
  850. });
  851. });