core.controller.tests.js 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. describe('Chart', function() {
  2. // https://github.com/chartjs/Chart.js/issues/2481
  3. // See global.deprecations.tests.js for backward compatibility
  4. it('should be defined and prototype of chart instances', function() {
  5. var chart = acquireChart({});
  6. expect(Chart).toBeDefined();
  7. expect(Chart instanceof Object).toBeTruthy();
  8. expect(chart.constructor).toBe(Chart);
  9. expect(chart instanceof Chart).toBeTruthy();
  10. expect(Chart.prototype.isPrototypeOf(chart)).toBeTruthy();
  11. });
  12. describe('config initialization', function() {
  13. it('should create missing config.data properties', function() {
  14. var chart = acquireChart({});
  15. var data = chart.data;
  16. expect(data instanceof Object).toBeTruthy();
  17. expect(data.labels instanceof Array).toBeTruthy();
  18. expect(data.labels.length).toBe(0);
  19. expect(data.datasets instanceof Array).toBeTruthy();
  20. expect(data.datasets.length).toBe(0);
  21. });
  22. it('should not alter config.data references', function() {
  23. var ds0 = {data: [10, 11, 12, 13]};
  24. var ds1 = {data: [20, 21, 22, 23]};
  25. var datasets = [ds0, ds1];
  26. var labels = [0, 1, 2, 3];
  27. var data = {labels: labels, datasets: datasets};
  28. var chart = acquireChart({
  29. type: 'line',
  30. data: data
  31. });
  32. expect(chart.data).toBe(data);
  33. expect(chart.data.labels).toBe(labels);
  34. expect(chart.data.datasets).toBe(datasets);
  35. expect(chart.data.datasets[0]).toBe(ds0);
  36. expect(chart.data.datasets[1]).toBe(ds1);
  37. expect(chart.data.datasets[0].data).toBe(ds0.data);
  38. expect(chart.data.datasets[1].data).toBe(ds1.data);
  39. });
  40. it('should define chart.data as an alias for config.data', function() {
  41. var config = {data: {labels: [], datasets: []}};
  42. var chart = acquireChart(config);
  43. expect(chart.data).toBe(config.data);
  44. chart.data = {labels: [1, 2, 3], datasets: [{data: [4, 5, 6]}]};
  45. expect(config.data).toBe(chart.data);
  46. expect(config.data.labels).toEqual([1, 2, 3]);
  47. expect(config.data.datasets[0].data).toEqual([4, 5, 6]);
  48. config.data = {labels: [7, 8, 9], datasets: [{data: [10, 11, 12]}]};
  49. expect(chart.data).toBe(config.data);
  50. expect(chart.data.labels).toEqual([7, 8, 9]);
  51. expect(chart.data.datasets[0].data).toEqual([10, 11, 12]);
  52. });
  53. it('should initialize config with default options', function() {
  54. var callback = function() {};
  55. var defaults = Chart.defaults;
  56. defaults.global.responsiveAnimationDuration = 42;
  57. defaults.global.hover.onHover = callback;
  58. defaults.line.hover.mode = 'x-axis';
  59. defaults.line.spanGaps = true;
  60. var chart = acquireChart({
  61. type: 'line'
  62. });
  63. var options = chart.options;
  64. expect(options.defaultFontSize).toBe(defaults.global.defaultFontSize);
  65. expect(options.showLines).toBe(defaults.line.showLines);
  66. expect(options.spanGaps).toBe(true);
  67. expect(options.responsiveAnimationDuration).toBe(42);
  68. expect(options.hover.onHover).toBe(callback);
  69. expect(options.hover.mode).toBe('x-axis');
  70. });
  71. it('should override default options', function() {
  72. var defaults = Chart.defaults;
  73. defaults.global.responsiveAnimationDuration = 42;
  74. defaults.line.hover.mode = 'x-axis';
  75. defaults.line.spanGaps = true;
  76. var chart = acquireChart({
  77. type: 'line',
  78. options: {
  79. responsiveAnimationDuration: 4242,
  80. spanGaps: false,
  81. hover: {
  82. mode: 'dataset',
  83. },
  84. title: {
  85. position: 'bottom'
  86. }
  87. }
  88. });
  89. var options = chart.options;
  90. expect(options.responsiveAnimationDuration).toBe(4242);
  91. expect(options.spanGaps).toBe(false);
  92. expect(options.hover.mode).toBe('dataset');
  93. expect(options.title.position).toBe('bottom');
  94. });
  95. it('should override axis positions that are incorrect', function() {
  96. var chart = acquireChart({
  97. type: 'line',
  98. options: {
  99. scales: {
  100. xAxes: [{
  101. position: 'left',
  102. }],
  103. yAxes: [{
  104. position: 'bottom'
  105. }]
  106. }
  107. }
  108. });
  109. var scaleOptions = chart.options.scales;
  110. expect(scaleOptions.xAxes[0].position).toBe('bottom');
  111. expect(scaleOptions.yAxes[0].position).toBe('left');
  112. });
  113. it('should throw an error if the chart type is incorrect', function() {
  114. function createChart() {
  115. acquireChart({
  116. type: 'area',
  117. data: {
  118. datasets: [{
  119. label: 'first',
  120. data: [10, 20]
  121. }],
  122. labels: ['0', '1'],
  123. },
  124. options: {
  125. scales: {
  126. xAxes: [{
  127. position: 'left',
  128. }],
  129. yAxes: [{
  130. position: 'bottom'
  131. }]
  132. }
  133. }
  134. });
  135. }
  136. expect(createChart).toThrow(new Error('"area" is not a chart type.'));
  137. });
  138. });
  139. describe('config.options.responsive: false', function() {
  140. it('should not inject the resizer element', function() {
  141. var chart = acquireChart({
  142. options: {
  143. responsive: false
  144. }
  145. });
  146. var wrapper = chart.canvas.parentNode;
  147. expect(wrapper.childNodes.length).toBe(1);
  148. expect(wrapper.firstChild.tagName).toBe('CANVAS');
  149. });
  150. });
  151. describe('config.options.responsive: true (maintainAspectRatio: false)', function() {
  152. it('should fill parent width and height', function() {
  153. var chart = acquireChart({
  154. options: {
  155. responsive: true,
  156. maintainAspectRatio: false
  157. }
  158. }, {
  159. canvas: {
  160. style: 'width: 150px; height: 245px'
  161. },
  162. wrapper: {
  163. style: 'width: 300px; height: 350px'
  164. }
  165. });
  166. expect(chart).toBeChartOfSize({
  167. dw: 300, dh: 350,
  168. rw: 300, rh: 350,
  169. });
  170. });
  171. it('should resize the canvas when parent width changes', function(done) {
  172. var chart = acquireChart({
  173. options: {
  174. responsive: true,
  175. maintainAspectRatio: false
  176. }
  177. }, {
  178. canvas: {
  179. style: ''
  180. },
  181. wrapper: {
  182. style: 'width: 300px; height: 350px; position: relative'
  183. }
  184. });
  185. expect(chart).toBeChartOfSize({
  186. dw: 300, dh: 350,
  187. rw: 300, rh: 350,
  188. });
  189. var wrapper = chart.canvas.parentNode;
  190. wrapper.style.width = '455px';
  191. waitForResize(chart, function() {
  192. expect(chart).toBeChartOfSize({
  193. dw: 455, dh: 350,
  194. rw: 455, rh: 350,
  195. });
  196. wrapper.style.width = '150px';
  197. waitForResize(chart, function() {
  198. expect(chart).toBeChartOfSize({
  199. dw: 150, dh: 350,
  200. rw: 150, rh: 350,
  201. });
  202. done();
  203. });
  204. });
  205. });
  206. it('should resize the canvas when parent height changes', function(done) {
  207. var chart = acquireChart({
  208. options: {
  209. responsive: true,
  210. maintainAspectRatio: false
  211. }
  212. }, {
  213. canvas: {
  214. style: ''
  215. },
  216. wrapper: {
  217. style: 'width: 300px; height: 350px; position: relative'
  218. }
  219. });
  220. expect(chart).toBeChartOfSize({
  221. dw: 300, dh: 350,
  222. rw: 300, rh: 350,
  223. });
  224. var wrapper = chart.canvas.parentNode;
  225. wrapper.style.height = '455px';
  226. waitForResize(chart, function() {
  227. expect(chart).toBeChartOfSize({
  228. dw: 300, dh: 455,
  229. rw: 300, rh: 455,
  230. });
  231. wrapper.style.height = '150px';
  232. waitForResize(chart, function() {
  233. expect(chart).toBeChartOfSize({
  234. dw: 300, dh: 150,
  235. rw: 300, rh: 150,
  236. });
  237. done();
  238. });
  239. });
  240. });
  241. it('should not include parent padding when resizing the canvas', function(done) {
  242. var chart = acquireChart({
  243. type: 'line',
  244. options: {
  245. responsive: true,
  246. maintainAspectRatio: false
  247. }
  248. }, {
  249. canvas: {
  250. style: ''
  251. },
  252. wrapper: {
  253. style: 'padding: 50px; width: 320px; height: 350px; position: relative'
  254. }
  255. });
  256. expect(chart).toBeChartOfSize({
  257. dw: 320, dh: 350,
  258. rw: 320, rh: 350,
  259. });
  260. var wrapper = chart.canvas.parentNode;
  261. wrapper.style.height = '355px';
  262. wrapper.style.width = '455px';
  263. waitForResize(chart, function() {
  264. expect(chart).toBeChartOfSize({
  265. dw: 455, dh: 355,
  266. rw: 455, rh: 355,
  267. });
  268. done();
  269. });
  270. });
  271. it('should resize the canvas when the canvas display style changes from "none" to "block"', function(done) {
  272. var chart = acquireChart({
  273. options: {
  274. responsive: true,
  275. maintainAspectRatio: false
  276. }
  277. }, {
  278. canvas: {
  279. style: 'display: none;'
  280. },
  281. wrapper: {
  282. style: 'width: 320px; height: 350px'
  283. }
  284. });
  285. var canvas = chart.canvas;
  286. canvas.style.display = 'block';
  287. waitForResize(chart, function() {
  288. expect(chart).toBeChartOfSize({
  289. dw: 320, dh: 350,
  290. rw: 320, rh: 350,
  291. });
  292. done();
  293. });
  294. });
  295. it('should resize the canvas when the wrapper display style changes from "none" to "block"', function(done) {
  296. var chart = acquireChart({
  297. options: {
  298. responsive: true,
  299. maintainAspectRatio: false
  300. }
  301. }, {
  302. canvas: {
  303. style: ''
  304. },
  305. wrapper: {
  306. style: 'display: none; width: 460px; height: 380px'
  307. }
  308. });
  309. var wrapper = chart.canvas.parentNode;
  310. wrapper.style.display = 'block';
  311. waitForResize(chart, function() {
  312. expect(chart).toBeChartOfSize({
  313. dw: 460, dh: 380,
  314. rw: 460, rh: 380,
  315. });
  316. done();
  317. });
  318. });
  319. // https://github.com/chartjs/Chart.js/issues/3790
  320. it('should resize the canvas if attached to the DOM after construction', function(done) {
  321. var canvas = document.createElement('canvas');
  322. var wrapper = document.createElement('div');
  323. var body = window.document.body;
  324. var chart = new Chart(canvas, {
  325. type: 'line',
  326. options: {
  327. responsive: true,
  328. maintainAspectRatio: false
  329. }
  330. });
  331. expect(chart).toBeChartOfSize({
  332. dw: 0, dh: 0,
  333. rw: 0, rh: 0,
  334. });
  335. wrapper.style.cssText = 'width: 455px; height: 355px';
  336. wrapper.appendChild(canvas);
  337. body.appendChild(wrapper);
  338. waitForResize(chart, function() {
  339. expect(chart).toBeChartOfSize({
  340. dw: 455, dh: 355,
  341. rw: 455, rh: 355,
  342. });
  343. body.removeChild(wrapper);
  344. chart.destroy();
  345. done();
  346. });
  347. });
  348. it('should resize the canvas when attached to a different parent', function(done) {
  349. var canvas = document.createElement('canvas');
  350. var wrapper = document.createElement('div');
  351. var body = window.document.body;
  352. var chart = new Chart(canvas, {
  353. type: 'line',
  354. options: {
  355. responsive: true,
  356. maintainAspectRatio: false
  357. }
  358. });
  359. expect(chart).toBeChartOfSize({
  360. dw: 0, dh: 0,
  361. rw: 0, rh: 0,
  362. });
  363. wrapper.style.cssText = 'width: 455px; height: 355px';
  364. wrapper.appendChild(canvas);
  365. body.appendChild(wrapper);
  366. waitForResize(chart, function() {
  367. var resizer = wrapper.firstChild;
  368. expect(resizer.className).toBe('chartjs-size-monitor');
  369. expect(resizer.tagName).toBe('DIV');
  370. expect(chart).toBeChartOfSize({
  371. dw: 455, dh: 355,
  372. rw: 455, rh: 355,
  373. });
  374. var target = document.createElement('div');
  375. target.style.cssText = 'width: 640px; height: 480px';
  376. target.appendChild(canvas);
  377. body.appendChild(target);
  378. waitForResize(chart, function() {
  379. expect(target.firstChild).toBe(resizer);
  380. expect(wrapper.firstChild).toBe(null);
  381. expect(chart).toBeChartOfSize({
  382. dw: 640, dh: 480,
  383. rw: 640, rh: 480,
  384. });
  385. body.removeChild(wrapper);
  386. body.removeChild(target);
  387. chart.destroy();
  388. done();
  389. });
  390. });
  391. });
  392. // https://github.com/chartjs/Chart.js/issues/3521
  393. it('should resize the canvas after the wrapper has been re-attached to the DOM', function(done) {
  394. var chart = acquireChart({
  395. options: {
  396. responsive: true,
  397. maintainAspectRatio: false
  398. }
  399. }, {
  400. canvas: {
  401. style: ''
  402. },
  403. wrapper: {
  404. style: 'width: 320px; height: 350px'
  405. }
  406. });
  407. expect(chart).toBeChartOfSize({
  408. dw: 320, dh: 350,
  409. rw: 320, rh: 350,
  410. });
  411. var wrapper = chart.canvas.parentNode;
  412. var parent = wrapper.parentNode;
  413. parent.removeChild(wrapper);
  414. parent.appendChild(wrapper);
  415. wrapper.style.height = '355px';
  416. waitForResize(chart, function() {
  417. expect(chart).toBeChartOfSize({
  418. dw: 320, dh: 355,
  419. rw: 320, rh: 355,
  420. });
  421. parent.removeChild(wrapper);
  422. wrapper.style.width = '455px';
  423. parent.appendChild(wrapper);
  424. waitForResize(chart, function() {
  425. expect(chart).toBeChartOfSize({
  426. dw: 455, dh: 355,
  427. rw: 455, rh: 355,
  428. });
  429. done();
  430. });
  431. });
  432. });
  433. // https://github.com/chartjs/Chart.js/issues/4737
  434. it('should resize the canvas when re-creating the chart', function(done) {
  435. var chart = acquireChart({
  436. options: {
  437. responsive: true
  438. }
  439. }, {
  440. wrapper: {
  441. style: 'width: 320px'
  442. }
  443. });
  444. waitForResize(chart, function() {
  445. var canvas = chart.canvas;
  446. expect(chart).toBeChartOfSize({
  447. dw: 320, dh: 320,
  448. rw: 320, rh: 320,
  449. });
  450. chart.destroy();
  451. chart = new Chart(canvas, {
  452. type: 'line',
  453. options: {
  454. responsive: true
  455. }
  456. });
  457. canvas.parentNode.style.width = '455px';
  458. waitForResize(chart, function() {
  459. expect(chart).toBeChartOfSize({
  460. dw: 455, dh: 455,
  461. rw: 455, rh: 455,
  462. });
  463. done();
  464. });
  465. });
  466. });
  467. });
  468. describe('config.options.responsive: true (maintainAspectRatio: true)', function() {
  469. it('should resize the canvas with correct aspect ratio when parent width changes', function(done) {
  470. var chart = acquireChart({
  471. type: 'line', // AR == 2
  472. options: {
  473. responsive: true,
  474. maintainAspectRatio: true
  475. }
  476. }, {
  477. canvas: {
  478. style: ''
  479. },
  480. wrapper: {
  481. style: 'width: 300px; height: 350px; position: relative'
  482. }
  483. });
  484. expect(chart).toBeChartOfSize({
  485. dw: 300, dh: 150,
  486. rw: 300, rh: 150,
  487. });
  488. var wrapper = chart.canvas.parentNode;
  489. wrapper.style.width = '450px';
  490. waitForResize(chart, function() {
  491. expect(chart).toBeChartOfSize({
  492. dw: 450, dh: 225,
  493. rw: 450, rh: 225,
  494. });
  495. wrapper.style.width = '150px';
  496. waitForResize(chart, function() {
  497. expect(chart).toBeChartOfSize({
  498. dw: 150, dh: 75,
  499. rw: 150, rh: 75,
  500. });
  501. done();
  502. });
  503. });
  504. });
  505. it('should not resize the canvas when parent height changes', function(done) {
  506. var chart = acquireChart({
  507. options: {
  508. responsive: true,
  509. maintainAspectRatio: true
  510. }
  511. }, {
  512. canvas: {
  513. style: ''
  514. },
  515. wrapper: {
  516. style: 'width: 320px; height: 350px; position: relative'
  517. }
  518. });
  519. expect(chart).toBeChartOfSize({
  520. dw: 320, dh: 160,
  521. rw: 320, rh: 160,
  522. });
  523. var wrapper = chart.canvas.parentNode;
  524. wrapper.style.height = '455px';
  525. waitForResize(chart, function() {
  526. expect(chart).toBeChartOfSize({
  527. dw: 320, dh: 160,
  528. rw: 320, rh: 160,
  529. });
  530. wrapper.style.height = '150px';
  531. waitForResize(chart, function() {
  532. expect(chart).toBeChartOfSize({
  533. dw: 320, dh: 160,
  534. rw: 320, rh: 160,
  535. });
  536. done();
  537. });
  538. });
  539. });
  540. });
  541. describe('Retina scale (a.k.a. device pixel ratio)', function() {
  542. beforeEach(function() {
  543. this.devicePixelRatio = window.devicePixelRatio;
  544. window.devicePixelRatio = 3;
  545. });
  546. afterEach(function() {
  547. window.devicePixelRatio = this.devicePixelRatio;
  548. });
  549. // see https://github.com/chartjs/Chart.js/issues/3575
  550. it ('should scale the render size but not the "implicit" display size', function() {
  551. var chart = acquireChart({
  552. options: {
  553. responsive: false
  554. }
  555. }, {
  556. canvas: {
  557. width: 320,
  558. height: 240,
  559. }
  560. });
  561. expect(chart).toBeChartOfSize({
  562. dw: 320, dh: 240,
  563. rw: 960, rh: 720,
  564. });
  565. });
  566. it ('should scale the render size but not the "explicit" display size', function() {
  567. var chart = acquireChart({
  568. options: {
  569. responsive: false
  570. }
  571. }, {
  572. canvas: {
  573. style: 'width: 320px; height: 240px'
  574. }
  575. });
  576. expect(chart).toBeChartOfSize({
  577. dw: 320, dh: 240,
  578. rw: 960, rh: 720,
  579. });
  580. });
  581. });
  582. describe('config.options.devicePixelRatio', function() {
  583. beforeEach(function() {
  584. this.devicePixelRatio = window.devicePixelRatio;
  585. window.devicePixelRatio = 1;
  586. });
  587. afterEach(function() {
  588. window.devicePixelRatio = this.devicePixelRatio;
  589. });
  590. // see https://github.com/chartjs/Chart.js/issues/3575
  591. it ('should scale the render size but not the "implicit" display size', function() {
  592. var chart = acquireChart({
  593. options: {
  594. responsive: false,
  595. devicePixelRatio: 3
  596. }
  597. }, {
  598. canvas: {
  599. width: 320,
  600. height: 240,
  601. }
  602. });
  603. expect(chart).toBeChartOfSize({
  604. dw: 320, dh: 240,
  605. rw: 960, rh: 720,
  606. });
  607. });
  608. it ('should scale the render size but not the "explicit" display size', function() {
  609. var chart = acquireChart({
  610. options: {
  611. responsive: false,
  612. devicePixelRatio: 3
  613. }
  614. }, {
  615. canvas: {
  616. style: 'width: 320px; height: 240px'
  617. }
  618. });
  619. expect(chart).toBeChartOfSize({
  620. dw: 320, dh: 240,
  621. rw: 960, rh: 720,
  622. });
  623. });
  624. });
  625. describe('controller.destroy', function() {
  626. it('should remove the resizer element when responsive: true', function(done) {
  627. var chart = acquireChart({
  628. options: {
  629. responsive: true
  630. }
  631. });
  632. waitForResize(chart, function() {
  633. var wrapper = chart.canvas.parentNode;
  634. var resizer = wrapper.firstChild;
  635. expect(wrapper.childNodes.length).toBe(2);
  636. expect(resizer.className).toBe('chartjs-size-monitor');
  637. expect(resizer.tagName).toBe('DIV');
  638. chart.destroy();
  639. expect(wrapper.childNodes.length).toBe(1);
  640. expect(wrapper.firstChild.tagName).toBe('CANVAS');
  641. done();
  642. });
  643. });
  644. });
  645. describe('controller.reset', function() {
  646. it('should reset the chart elements', function() {
  647. var chart = acquireChart({
  648. type: 'line',
  649. data: {
  650. labels: ['A', 'B', 'C', 'D'],
  651. datasets: [{
  652. data: [10, 20, 30, 0]
  653. }]
  654. },
  655. options: {
  656. responsive: true
  657. }
  658. });
  659. var meta = chart.getDatasetMeta(0);
  660. // Verify that points are at their initial correct location,
  661. // then we will reset and see that they moved
  662. expect(meta.data[0]._model.y).toBeCloseToPixel(333);
  663. expect(meta.data[1]._model.y).toBeCloseToPixel(183);
  664. expect(meta.data[2]._model.y).toBe(32);
  665. expect(meta.data[3]._model.y).toBe(484);
  666. chart.reset();
  667. // For a line chart, the animation state is the bottom
  668. expect(meta.data[0]._model.y).toBe(484);
  669. expect(meta.data[1]._model.y).toBe(484);
  670. expect(meta.data[2]._model.y).toBe(484);
  671. expect(meta.data[3]._model.y).toBe(484);
  672. });
  673. });
  674. describe('config update', function() {
  675. it ('should update options', function() {
  676. var chart = acquireChart({
  677. type: 'line',
  678. data: {
  679. labels: ['A', 'B', 'C', 'D'],
  680. datasets: [{
  681. data: [10, 20, 30, 100]
  682. }]
  683. },
  684. options: {
  685. responsive: true
  686. }
  687. });
  688. chart.options = {
  689. responsive: false,
  690. scales: {
  691. yAxes: [{
  692. ticks: {
  693. min: 0,
  694. max: 10
  695. }
  696. }]
  697. }
  698. };
  699. chart.update();
  700. var yScale = chart.scales['y-axis-0'];
  701. expect(yScale.options.ticks.min).toBe(0);
  702. expect(yScale.options.ticks.max).toBe(10);
  703. });
  704. it ('should update scales options', function() {
  705. var chart = acquireChart({
  706. type: 'line',
  707. data: {
  708. labels: ['A', 'B', 'C', 'D'],
  709. datasets: [{
  710. data: [10, 20, 30, 100]
  711. }]
  712. },
  713. options: {
  714. responsive: true
  715. }
  716. });
  717. chart.options.scales.yAxes[0].ticks.min = 0;
  718. chart.options.scales.yAxes[0].ticks.max = 10;
  719. chart.update();
  720. var yScale = chart.scales['y-axis-0'];
  721. expect(yScale.options.ticks.min).toBe(0);
  722. expect(yScale.options.ticks.max).toBe(10);
  723. });
  724. it ('should update scales options from new object', function() {
  725. var chart = acquireChart({
  726. type: 'line',
  727. data: {
  728. labels: ['A', 'B', 'C', 'D'],
  729. datasets: [{
  730. data: [10, 20, 30, 100]
  731. }]
  732. },
  733. options: {
  734. responsive: true
  735. }
  736. });
  737. var newScalesConfig = {
  738. yAxes: [{
  739. ticks: {
  740. min: 0,
  741. max: 10
  742. }
  743. }]
  744. };
  745. chart.options.scales = newScalesConfig;
  746. chart.update();
  747. var yScale = chart.scales['y-axis-0'];
  748. expect(yScale.options.ticks.min).toBe(0);
  749. expect(yScale.options.ticks.max).toBe(10);
  750. });
  751. it ('should remove discarded scale', function() {
  752. var chart = acquireChart({
  753. type: 'line',
  754. data: {
  755. labels: ['A', 'B', 'C', 'D'],
  756. datasets: [{
  757. data: [10, 20, 30, 100]
  758. }]
  759. },
  760. options: {
  761. responsive: true,
  762. scales: {
  763. yAxes: [{
  764. id: 'yAxis0',
  765. ticks: {
  766. min: 0,
  767. max: 10
  768. }
  769. }]
  770. }
  771. }
  772. });
  773. var newScalesConfig = {
  774. yAxes: [{
  775. ticks: {
  776. min: 0,
  777. max: 10
  778. }
  779. }]
  780. };
  781. chart.options.scales = newScalesConfig;
  782. chart.update();
  783. var yScale = chart.scales.yAxis0;
  784. expect(yScale).toBeUndefined();
  785. var newyScale = chart.scales['y-axis-0'];
  786. expect(newyScale.options.ticks.min).toBe(0);
  787. expect(newyScale.options.ticks.max).toBe(10);
  788. });
  789. it ('should update tooltip options', function() {
  790. var chart = acquireChart({
  791. type: 'line',
  792. data: {
  793. labels: ['A', 'B', 'C', 'D'],
  794. datasets: [{
  795. data: [10, 20, 30, 100]
  796. }]
  797. },
  798. options: {
  799. responsive: true
  800. }
  801. });
  802. var newTooltipConfig = {
  803. mode: 'dataset',
  804. intersect: false
  805. };
  806. chart.options.tooltips = newTooltipConfig;
  807. chart.update();
  808. expect(chart.tooltip._options).toEqual(jasmine.objectContaining(newTooltipConfig));
  809. });
  810. it ('should reset the tooltip on update', function() {
  811. var chart = acquireChart({
  812. type: 'line',
  813. data: {
  814. labels: ['A', 'B', 'C', 'D'],
  815. datasets: [{
  816. data: [10, 20, 30, 100]
  817. }]
  818. },
  819. options: {
  820. responsive: true,
  821. tooltip: {
  822. mode: 'nearest'
  823. }
  824. }
  825. });
  826. // Trigger an event over top of a point to
  827. // put an item into the tooltip
  828. var meta = chart.getDatasetMeta(0);
  829. var point = meta.data[1];
  830. var node = chart.canvas;
  831. var rect = node.getBoundingClientRect();
  832. var evt = new MouseEvent('mousemove', {
  833. view: window,
  834. bubbles: true,
  835. cancelable: true,
  836. clientX: rect.left + point._model.x,
  837. clientY: 0
  838. });
  839. // Manually trigger rather than having an async test
  840. node.dispatchEvent(evt);
  841. // Check and see if tooltip was displayed
  842. var tooltip = chart.tooltip;
  843. expect(chart.lastActive).toEqual([point]);
  844. expect(tooltip._lastActive).toEqual([]);
  845. // Update and confirm tooltip is reset
  846. chart.update();
  847. expect(chart.lastActive).toEqual([]);
  848. expect(tooltip._lastActive).toEqual([]);
  849. });
  850. it ('should update the metadata', function() {
  851. var cfg = {
  852. data: {
  853. labels: ['A', 'B', 'C', 'D'],
  854. datasets: [{
  855. type: 'line',
  856. data: [10, 20, 30, 0]
  857. }]
  858. },
  859. options: {
  860. responsive: true,
  861. scales: {
  862. xAxes: [{
  863. type: 'time'
  864. }],
  865. yAxes: [{
  866. scaleLabel: {
  867. display: true,
  868. labelString: 'Value'
  869. }
  870. }]
  871. }
  872. }
  873. };
  874. var chart = acquireChart(cfg);
  875. var meta = chart.getDatasetMeta(0);
  876. expect(meta.type).toBe('line');
  877. // change the dataset to bar and check that meta was updated
  878. chart.config.data.datasets[0].type = 'bar';
  879. chart.update();
  880. meta = chart.getDatasetMeta(0);
  881. expect(meta.type).toBe('bar');
  882. });
  883. });
  884. describe('plugin.extensions', function() {
  885. it ('should notify plugin in correct order', function(done) {
  886. var plugin = this.plugin = {};
  887. var sequence = [];
  888. var hooks = {
  889. init: [
  890. 'beforeInit',
  891. 'afterInit'
  892. ],
  893. update: [
  894. 'beforeUpdate',
  895. 'beforeLayout',
  896. 'afterLayout',
  897. 'beforeDatasetsUpdate',
  898. 'beforeDatasetUpdate',
  899. 'afterDatasetUpdate',
  900. 'afterDatasetsUpdate',
  901. 'afterUpdate',
  902. ],
  903. render: [
  904. 'beforeRender',
  905. 'beforeDraw',
  906. 'beforeDatasetsDraw',
  907. 'beforeDatasetDraw',
  908. 'afterDatasetDraw',
  909. 'afterDatasetsDraw',
  910. 'beforeTooltipDraw',
  911. 'afterTooltipDraw',
  912. 'afterDraw',
  913. 'afterRender',
  914. ],
  915. resize: [
  916. 'resize'
  917. ],
  918. destroy: [
  919. 'destroy'
  920. ]
  921. };
  922. Object.keys(hooks).forEach(function(group) {
  923. hooks[group].forEach(function(name) {
  924. plugin[name] = function() {
  925. sequence.push(name);
  926. };
  927. });
  928. });
  929. var chart = window.acquireChart({
  930. type: 'line',
  931. data: {datasets: [{}]},
  932. plugins: [plugin],
  933. options: {
  934. responsive: true
  935. }
  936. }, {
  937. wrapper: {
  938. style: 'width: 300px'
  939. }
  940. });
  941. chart.canvas.parentNode.style.width = '400px';
  942. waitForResize(chart, function() {
  943. chart.destroy();
  944. expect(sequence).toEqual([].concat(
  945. hooks.init,
  946. hooks.update,
  947. hooks.render,
  948. hooks.resize,
  949. hooks.update,
  950. hooks.render,
  951. hooks.destroy
  952. ));
  953. done();
  954. });
  955. });
  956. it('should not notify before/afterDatasetDraw if dataset is hidden', function() {
  957. var sequence = [];
  958. var plugin = this.plugin = {
  959. beforeDatasetDraw: function(chart, args) {
  960. sequence.push('before-' + args.index);
  961. },
  962. afterDatasetDraw: function(chart, args) {
  963. sequence.push('after-' + args.index);
  964. }
  965. };
  966. window.acquireChart({
  967. type: 'line',
  968. data: {datasets: [{}, {hidden: true}, {}]},
  969. plugins: [plugin]
  970. });
  971. expect(sequence).toEqual([
  972. 'before-2', 'after-2',
  973. 'before-0', 'after-0'
  974. ]);
  975. });
  976. });
  977. describe('controller.update', function() {
  978. beforeEach(function() {
  979. this.chart = acquireChart({
  980. type: 'doughnut',
  981. options: {
  982. animation: {
  983. easing: 'linear',
  984. duration: 500
  985. }
  986. }
  987. });
  988. this.addAnimationSpy = spyOn(Chart.animationService, 'addAnimation');
  989. });
  990. it('should add an animation with the default options', function() {
  991. this.chart.update();
  992. expect(this.addAnimationSpy).toHaveBeenCalledWith(
  993. this.chart,
  994. jasmine.objectContaining({easing: 'linear'}),
  995. undefined,
  996. undefined
  997. );
  998. });
  999. it('should add an animation with the provided options', function() {
  1000. this.chart.update({
  1001. duration: 800,
  1002. easing: 'easeOutBounce',
  1003. lazy: false,
  1004. });
  1005. expect(this.addAnimationSpy).toHaveBeenCalledWith(
  1006. this.chart,
  1007. jasmine.objectContaining({easing: 'easeOutBounce'}),
  1008. 800,
  1009. false
  1010. );
  1011. });
  1012. });
  1013. });