core.helpers.tests.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. describe('Core helper tests', function() {
  2. var helpers;
  3. beforeAll(function() {
  4. helpers = window.Chart.helpers;
  5. });
  6. it('should merge a normal config without scales', function() {
  7. var baseConfig = {
  8. valueProp: 5,
  9. arrayProp: [1, 2, 3, 4, 5, 6],
  10. objectProp: {
  11. prop1: 'abc',
  12. prop2: 56
  13. }
  14. };
  15. var toMerge = {
  16. valueProp2: null,
  17. arrayProp: ['a', 'c'],
  18. objectProp: {
  19. prop1: 'c',
  20. prop3: 'prop3'
  21. }
  22. };
  23. var merged = helpers.configMerge(baseConfig, toMerge);
  24. expect(merged).toEqual({
  25. valueProp: 5,
  26. valueProp2: null,
  27. arrayProp: ['a', 'c'],
  28. objectProp: {
  29. prop1: 'c',
  30. prop2: 56,
  31. prop3: 'prop3'
  32. }
  33. });
  34. });
  35. it('should merge scale configs', function() {
  36. var baseConfig = {
  37. scales: {
  38. prop1: {
  39. abc: 123,
  40. def: '456'
  41. },
  42. prop2: 777,
  43. yAxes: [{
  44. type: 'linear',
  45. }, {
  46. type: 'log'
  47. }]
  48. }
  49. };
  50. var toMerge = {
  51. scales: {
  52. prop1: {
  53. def: 'bbb',
  54. ghi: 78
  55. },
  56. prop2: null,
  57. yAxes: [{
  58. type: 'linear',
  59. axisProp: 456
  60. }, {
  61. // pulls in linear default config since axis type changes
  62. type: 'linear',
  63. position: 'right'
  64. }, {
  65. // Pulls in linear default config since axis not in base
  66. type: 'linear'
  67. }]
  68. }
  69. };
  70. var merged = helpers.configMerge(baseConfig, toMerge);
  71. expect(merged).toEqual({
  72. scales: {
  73. prop1: {
  74. abc: 123,
  75. def: 'bbb',
  76. ghi: 78
  77. },
  78. prop2: null,
  79. yAxes: [{
  80. type: 'linear',
  81. axisProp: 456
  82. }, {
  83. display: true,
  84. gridLines: {
  85. color: 'rgba(0, 0, 0, 0.1)',
  86. drawBorder: true,
  87. drawOnChartArea: true,
  88. drawTicks: true, // draw ticks extending towards the label
  89. tickMarkLength: 10,
  90. lineWidth: 1,
  91. offsetGridLines: false,
  92. display: true,
  93. zeroLineColor: 'rgba(0,0,0,0.25)',
  94. zeroLineWidth: 1,
  95. zeroLineBorderDash: [],
  96. zeroLineBorderDashOffset: 0.0,
  97. borderDash: [],
  98. borderDashOffset: 0.0
  99. },
  100. position: 'right',
  101. offset: false,
  102. scaleLabel: Chart.defaults.scale.scaleLabel,
  103. ticks: {
  104. beginAtZero: false,
  105. minRotation: 0,
  106. maxRotation: 50,
  107. mirror: false,
  108. padding: 0,
  109. reverse: false,
  110. display: true,
  111. callback: merged.scales.yAxes[1].ticks.callback, // make it nicer, then check explicitly below
  112. autoSkip: true,
  113. autoSkipPadding: 0,
  114. labelOffset: 0,
  115. minor: {},
  116. major: {},
  117. },
  118. type: 'linear'
  119. }, {
  120. display: true,
  121. gridLines: {
  122. color: 'rgba(0, 0, 0, 0.1)',
  123. drawBorder: true,
  124. drawOnChartArea: true,
  125. drawTicks: true, // draw ticks extending towards the label,
  126. tickMarkLength: 10,
  127. lineWidth: 1,
  128. offsetGridLines: false,
  129. display: true,
  130. zeroLineColor: 'rgba(0,0,0,0.25)',
  131. zeroLineWidth: 1,
  132. zeroLineBorderDash: [],
  133. zeroLineBorderDashOffset: 0.0,
  134. borderDash: [],
  135. borderDashOffset: 0.0
  136. },
  137. position: 'left',
  138. offset: false,
  139. scaleLabel: Chart.defaults.scale.scaleLabel,
  140. ticks: {
  141. beginAtZero: false,
  142. minRotation: 0,
  143. maxRotation: 50,
  144. mirror: false,
  145. padding: 0,
  146. reverse: false,
  147. display: true,
  148. callback: merged.scales.yAxes[2].ticks.callback, // make it nicer, then check explicitly below
  149. autoSkip: true,
  150. autoSkipPadding: 0,
  151. labelOffset: 0,
  152. minor: {},
  153. major: {},
  154. },
  155. type: 'linear'
  156. }]
  157. }
  158. });
  159. // Are these actually functions
  160. expect(merged.scales.yAxes[1].ticks.callback).toEqual(jasmine.any(Function));
  161. expect(merged.scales.yAxes[2].ticks.callback).toEqual(jasmine.any(Function));
  162. });
  163. it('should filter an array', function() {
  164. var data = [-10, 0, 6, 0, 7];
  165. var callback = function(item) {
  166. return item > 2;
  167. };
  168. expect(helpers.where(data, callback)).toEqual([6, 7]);
  169. expect(helpers.findNextWhere(data, callback)).toEqual(6);
  170. expect(helpers.findNextWhere(data, callback, 2)).toBe(7);
  171. expect(helpers.findNextWhere(data, callback, 4)).toBe(undefined);
  172. expect(helpers.findPreviousWhere(data, callback)).toBe(7);
  173. expect(helpers.findPreviousWhere(data, callback, 3)).toBe(6);
  174. expect(helpers.findPreviousWhere(data, callback, 0)).toBe(undefined);
  175. });
  176. it('should get the correct sign', function() {
  177. expect(helpers.sign(0)).toBe(0);
  178. expect(helpers.sign(10)).toBe(1);
  179. expect(helpers.sign(-5)).toBe(-1);
  180. });
  181. it('should do a log10 operation', function() {
  182. expect(helpers.log10(0)).toBe(-Infinity);
  183. // Check all allowed powers of 10, which should return integer values
  184. var maxPowerOf10 = Math.floor(helpers.log10(Number.MAX_VALUE));
  185. for (var i = 0; i < maxPowerOf10; i += 1) {
  186. expect(helpers.log10(Math.pow(10, i))).toBe(i);
  187. }
  188. });
  189. it('should correctly determine if two numbers are essentially equal', function() {
  190. expect(helpers.almostEquals(0, Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
  191. expect(helpers.almostEquals(1, 1.1, 0.0001)).toBe(false);
  192. expect(helpers.almostEquals(1e30, 1e30 + Number.EPSILON, 0)).toBe(false);
  193. expect(helpers.almostEquals(1e30, 1e30 + Number.EPSILON, 2 * Number.EPSILON)).toBe(true);
  194. });
  195. it('should correctly determine if a numbers are essentially whole', function() {
  196. expect(helpers.almostWhole(0.99999, 0.0001)).toBe(true);
  197. expect(helpers.almostWhole(0.9, 0.0001)).toBe(false);
  198. });
  199. it('should generate integer ids', function() {
  200. var uid = helpers.uid();
  201. expect(uid).toEqual(jasmine.any(Number));
  202. expect(helpers.uid()).toBe(uid + 1);
  203. expect(helpers.uid()).toBe(uid + 2);
  204. expect(helpers.uid()).toBe(uid + 3);
  205. });
  206. it('should detect a number', function() {
  207. expect(helpers.isNumber(123)).toBe(true);
  208. expect(helpers.isNumber('123')).toBe(true);
  209. expect(helpers.isNumber(null)).toBe(false);
  210. expect(helpers.isNumber(NaN)).toBe(false);
  211. expect(helpers.isNumber(undefined)).toBe(false);
  212. expect(helpers.isNumber('cbc')).toBe(false);
  213. });
  214. it('should convert between radians and degrees', function() {
  215. expect(helpers.toRadians(180)).toBe(Math.PI);
  216. expect(helpers.toRadians(90)).toBe(0.5 * Math.PI);
  217. expect(helpers.toDegrees(Math.PI)).toBe(180);
  218. expect(helpers.toDegrees(Math.PI * 3 / 2)).toBe(270);
  219. });
  220. it('should get an angle from a point', function() {
  221. var center = {
  222. x: 0,
  223. y: 0
  224. };
  225. expect(helpers.getAngleFromPoint(center, {
  226. x: 0,
  227. y: 10
  228. })).toEqual({
  229. angle: Math.PI / 2,
  230. distance: 10,
  231. });
  232. expect(helpers.getAngleFromPoint(center, {
  233. x: Math.sqrt(2),
  234. y: Math.sqrt(2)
  235. })).toEqual({
  236. angle: Math.PI / 4,
  237. distance: 2
  238. });
  239. expect(helpers.getAngleFromPoint(center, {
  240. x: -1.0 * Math.sqrt(2),
  241. y: -1.0 * Math.sqrt(2)
  242. })).toEqual({
  243. angle: Math.PI * 1.25,
  244. distance: 2
  245. });
  246. });
  247. it('should spline curves', function() {
  248. expect(helpers.splineCurve({
  249. x: 0,
  250. y: 0
  251. }, {
  252. x: 1,
  253. y: 1
  254. }, {
  255. x: 2,
  256. y: 0
  257. }, 0)).toEqual({
  258. previous: {
  259. x: 1,
  260. y: 1,
  261. },
  262. next: {
  263. x: 1,
  264. y: 1,
  265. }
  266. });
  267. expect(helpers.splineCurve({
  268. x: 0,
  269. y: 0
  270. }, {
  271. x: 1,
  272. y: 1
  273. }, {
  274. x: 2,
  275. y: 0
  276. }, 1)).toEqual({
  277. previous: {
  278. x: 0,
  279. y: 1,
  280. },
  281. next: {
  282. x: 2,
  283. y: 1,
  284. }
  285. });
  286. });
  287. it('should spline curves with monotone cubic interpolation', function() {
  288. var dataPoints = [
  289. {_model: {x: 0, y: 0, skip: false}},
  290. {_model: {x: 3, y: 6, skip: false}},
  291. {_model: {x: 9, y: 6, skip: false}},
  292. {_model: {x: 12, y: 60, skip: false}},
  293. {_model: {x: 15, y: 60, skip: false}},
  294. {_model: {x: 18, y: 120, skip: false}},
  295. {_model: {x: null, y: null, skip: true}},
  296. {_model: {x: 21, y: 180, skip: false}},
  297. {_model: {x: 24, y: 120, skip: false}},
  298. {_model: {x: 27, y: 125, skip: false}},
  299. {_model: {x: 30, y: 105, skip: false}},
  300. {_model: {x: 33, y: 110, skip: false}},
  301. {_model: {x: 33, y: 110, skip: false}},
  302. {_model: {x: 36, y: 170, skip: false}}
  303. ];
  304. helpers.splineCurveMonotone(dataPoints);
  305. expect(dataPoints).toEqual([{
  306. _model: {
  307. x: 0,
  308. y: 0,
  309. skip: false,
  310. controlPointNextX: 1,
  311. controlPointNextY: 2
  312. }
  313. },
  314. {
  315. _model: {
  316. x: 3,
  317. y: 6,
  318. skip: false,
  319. controlPointPreviousX: 2,
  320. controlPointPreviousY: 6,
  321. controlPointNextX: 5,
  322. controlPointNextY: 6
  323. }
  324. },
  325. {
  326. _model: {
  327. x: 9,
  328. y: 6,
  329. skip: false,
  330. controlPointPreviousX: 7,
  331. controlPointPreviousY: 6,
  332. controlPointNextX: 10,
  333. controlPointNextY: 6
  334. }
  335. },
  336. {
  337. _model: {
  338. x: 12,
  339. y: 60,
  340. skip: false,
  341. controlPointPreviousX: 11,
  342. controlPointPreviousY: 60,
  343. controlPointNextX: 13,
  344. controlPointNextY: 60
  345. }
  346. },
  347. {
  348. _model: {
  349. x: 15,
  350. y: 60,
  351. skip: false,
  352. controlPointPreviousX: 14,
  353. controlPointPreviousY: 60,
  354. controlPointNextX: 16,
  355. controlPointNextY: 60
  356. }
  357. },
  358. {
  359. _model: {
  360. x: 18,
  361. y: 120,
  362. skip: false,
  363. controlPointPreviousX: 17,
  364. controlPointPreviousY: 100
  365. }
  366. },
  367. {
  368. _model: {
  369. x: null,
  370. y: null,
  371. skip: true
  372. }
  373. },
  374. {
  375. _model: {
  376. x: 21,
  377. y: 180,
  378. skip: false,
  379. controlPointNextX: 22,
  380. controlPointNextY: 160
  381. }
  382. },
  383. {
  384. _model: {
  385. x: 24,
  386. y: 120,
  387. skip: false,
  388. controlPointPreviousX: 23,
  389. controlPointPreviousY: 120,
  390. controlPointNextX: 25,
  391. controlPointNextY: 120
  392. }
  393. },
  394. {
  395. _model: {
  396. x: 27,
  397. y: 125,
  398. skip: false,
  399. controlPointPreviousX: 26,
  400. controlPointPreviousY: 125,
  401. controlPointNextX: 28,
  402. controlPointNextY: 125
  403. }
  404. },
  405. {
  406. _model: {
  407. x: 30,
  408. y: 105,
  409. skip: false,
  410. controlPointPreviousX: 29,
  411. controlPointPreviousY: 105,
  412. controlPointNextX: 31,
  413. controlPointNextY: 105
  414. }
  415. },
  416. {
  417. _model: {
  418. x: 33,
  419. y: 110,
  420. skip: false,
  421. controlPointPreviousX: 32,
  422. controlPointPreviousY: 110,
  423. controlPointNextX: 33,
  424. controlPointNextY: 110
  425. }
  426. },
  427. {
  428. _model: {
  429. x: 33,
  430. y: 110,
  431. skip: false,
  432. controlPointPreviousX: 33,
  433. controlPointPreviousY: 110,
  434. controlPointNextX: 34,
  435. controlPointNextY: 110
  436. }
  437. },
  438. {
  439. _model: {
  440. x: 36,
  441. y: 170,
  442. skip: false,
  443. controlPointPreviousX: 35,
  444. controlPointPreviousY: 150
  445. }
  446. }]);
  447. });
  448. it('should get the next or previous item in an array', function() {
  449. var testData = [0, 1, 2];
  450. expect(helpers.nextItem(testData, 0, false)).toEqual(1);
  451. expect(helpers.nextItem(testData, 2, false)).toEqual(2);
  452. expect(helpers.nextItem(testData, 2, true)).toEqual(0);
  453. expect(helpers.nextItem(testData, 1, true)).toEqual(2);
  454. expect(helpers.nextItem(testData, -1, false)).toEqual(0);
  455. expect(helpers.previousItem(testData, 0, false)).toEqual(0);
  456. expect(helpers.previousItem(testData, 0, true)).toEqual(2);
  457. expect(helpers.previousItem(testData, 2, false)).toEqual(1);
  458. expect(helpers.previousItem(testData, 1, true)).toEqual(0);
  459. });
  460. it('should return the width of the longest text in an Array and 2D Array', function() {
  461. var context = window.createMockContext();
  462. var font = "normal 12px 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif";
  463. var arrayOfThings1D = ['FooBar', 'Bar'];
  464. var arrayOfThings2D = [['FooBar_1', 'Bar_2'], 'Foo_1'];
  465. // Regardless 'FooBar' is the longest label it should return (characters * 10)
  466. expect(helpers.longestText(context, font, arrayOfThings1D, {})).toEqual(60);
  467. expect(helpers.longestText(context, font, arrayOfThings2D, {})).toEqual(80);
  468. // We check to make sure we made the right calls to the canvas.
  469. expect(context.getCalls()).toEqual([{
  470. name: 'measureText',
  471. args: ['FooBar']
  472. }, {
  473. name: 'measureText',
  474. args: ['Bar']
  475. }, {
  476. name: 'measureText',
  477. args: ['FooBar_1']
  478. }, {
  479. name: 'measureText',
  480. args: ['Bar_2']
  481. }, {
  482. name: 'measureText',
  483. args: ['Foo_1']
  484. }]);
  485. });
  486. it('compare text with current longest and update', function() {
  487. var context = window.createMockContext();
  488. var data = {};
  489. var gc = [];
  490. var longest = 70;
  491. expect(helpers.measureText(context, data, gc, longest, 'foobar')).toEqual(70);
  492. expect(helpers.measureText(context, data, gc, longest, 'foobar_')).toEqual(70);
  493. expect(helpers.measureText(context, data, gc, longest, 'foobar_1')).toEqual(80);
  494. // We check to make sure we made the right calls to the canvas.
  495. expect(context.getCalls()).toEqual([{
  496. name: 'measureText',
  497. args: ['foobar']
  498. }, {
  499. name: 'measureText',
  500. args: ['foobar_']
  501. }, {
  502. name: 'measureText',
  503. args: ['foobar_1']
  504. }]);
  505. });
  506. it('count look at all the labels and return maximum number of lines', function() {
  507. window.createMockContext();
  508. var arrayOfThings1 = ['Foo', 'Bar'];
  509. var arrayOfThings2 = [['Foo', 'Bar'], 'Foo'];
  510. var arrayOfThings3 = [['Foo', 'Bar', 'Boo'], ['Foo', 'Bar'], 'Foo'];
  511. expect(helpers.numberOfLabelLines(arrayOfThings1)).toEqual(1);
  512. expect(helpers.numberOfLabelLines(arrayOfThings2)).toEqual(2);
  513. expect(helpers.numberOfLabelLines(arrayOfThings3)).toEqual(3);
  514. });
  515. it ('should get the maximum width and height for a node', function() {
  516. // Create div with fixed size as a test bed
  517. var div = document.createElement('div');
  518. div.style.width = '200px';
  519. div.style.height = '300px';
  520. document.body.appendChild(div);
  521. // Create the div we want to get the max size for
  522. var innerDiv = document.createElement('div');
  523. div.appendChild(innerDiv);
  524. expect(helpers.getMaximumWidth(innerDiv)).toBe(200);
  525. expect(helpers.getMaximumHeight(innerDiv)).toBe(300);
  526. document.body.removeChild(div);
  527. });
  528. it ('should get the maximum width of a node that has a max-width style', function() {
  529. // Create div with fixed size as a test bed
  530. var div = document.createElement('div');
  531. div.style.width = '200px';
  532. div.style.height = '300px';
  533. document.body.appendChild(div);
  534. // Create the div we want to get the max size for and set a max-width style
  535. var innerDiv = document.createElement('div');
  536. innerDiv.style.maxWidth = '150px';
  537. div.appendChild(innerDiv);
  538. expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
  539. document.body.removeChild(div);
  540. });
  541. it ('should get the maximum height of a node that has a max-height style', function() {
  542. // Create div with fixed size as a test bed
  543. var div = document.createElement('div');
  544. div.style.width = '200px';
  545. div.style.height = '300px';
  546. document.body.appendChild(div);
  547. // Create the div we want to get the max size for and set a max-height style
  548. var innerDiv = document.createElement('div');
  549. innerDiv.style.maxHeight = '150px';
  550. div.appendChild(innerDiv);
  551. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  552. document.body.removeChild(div);
  553. });
  554. it ('should get the maximum width of a node when the parent has a max-width style', function() {
  555. // Create div with fixed size as a test bed
  556. var div = document.createElement('div');
  557. div.style.width = '200px';
  558. div.style.height = '300px';
  559. document.body.appendChild(div);
  560. // Create an inner wrapper around our div we want to size and give that a max-width style
  561. var parentDiv = document.createElement('div');
  562. parentDiv.style.maxWidth = '150px';
  563. div.appendChild(parentDiv);
  564. // Create the div we want to get the max size for
  565. var innerDiv = document.createElement('div');
  566. parentDiv.appendChild(innerDiv);
  567. expect(helpers.getMaximumWidth(innerDiv)).toBe(150);
  568. document.body.removeChild(div);
  569. });
  570. it ('should get the maximum height of a node when the parent has a max-height style', function() {
  571. // Create div with fixed size as a test bed
  572. var div = document.createElement('div');
  573. div.style.width = '200px';
  574. div.style.height = '300px';
  575. document.body.appendChild(div);
  576. // Create an inner wrapper around our div we want to size and give that a max-height style
  577. var parentDiv = document.createElement('div');
  578. parentDiv.style.maxHeight = '150px';
  579. div.appendChild(parentDiv);
  580. // Create the div we want to get the max size for
  581. var innerDiv = document.createElement('div');
  582. innerDiv.style.height = '300px'; // make it large
  583. parentDiv.appendChild(innerDiv);
  584. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  585. document.body.removeChild(div);
  586. });
  587. it ('should get the maximum width of a node that has a percentage max-width style', function() {
  588. // Create div with fixed size as a test bed
  589. var div = document.createElement('div');
  590. div.style.width = '200px';
  591. div.style.height = '300px';
  592. document.body.appendChild(div);
  593. // Create the div we want to get the max size for and set a max-width style
  594. var innerDiv = document.createElement('div');
  595. innerDiv.style.maxWidth = '50%';
  596. div.appendChild(innerDiv);
  597. expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
  598. document.body.removeChild(div);
  599. });
  600. it ('should get the maximum height of a node that has a percentage max-height style', function() {
  601. // Create div with fixed size as a test bed
  602. var div = document.createElement('div');
  603. div.style.width = '200px';
  604. div.style.height = '300px';
  605. document.body.appendChild(div);
  606. // Create the div we want to get the max size for and set a max-height style
  607. var innerDiv = document.createElement('div');
  608. innerDiv.style.maxHeight = '50%';
  609. div.appendChild(innerDiv);
  610. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  611. document.body.removeChild(div);
  612. });
  613. it ('should get the maximum width of a node when the parent has a percentage max-width style', function() {
  614. // Create div with fixed size as a test bed
  615. var div = document.createElement('div');
  616. div.style.width = '200px';
  617. div.style.height = '300px';
  618. document.body.appendChild(div);
  619. // Create an inner wrapper around our div we want to size and give that a max-width style
  620. var parentDiv = document.createElement('div');
  621. parentDiv.style.maxWidth = '50%';
  622. div.appendChild(parentDiv);
  623. // Create the div we want to get the max size for
  624. var innerDiv = document.createElement('div');
  625. parentDiv.appendChild(innerDiv);
  626. expect(helpers.getMaximumWidth(innerDiv)).toBe(100);
  627. document.body.removeChild(div);
  628. });
  629. it ('should get the maximum height of a node when the parent has a percentage max-height style', function() {
  630. // Create div with fixed size as a test bed
  631. var div = document.createElement('div');
  632. div.style.width = '200px';
  633. div.style.height = '300px';
  634. document.body.appendChild(div);
  635. // Create an inner wrapper around our div we want to size and give that a max-height style
  636. var parentDiv = document.createElement('div');
  637. parentDiv.style.maxHeight = '50%';
  638. div.appendChild(parentDiv);
  639. var innerDiv = document.createElement('div');
  640. innerDiv.style.height = '300px'; // make it large
  641. parentDiv.appendChild(innerDiv);
  642. expect(helpers.getMaximumHeight(innerDiv)).toBe(150);
  643. document.body.removeChild(div);
  644. });
  645. it ('should leave styled height and width on canvas if explicitly set', function() {
  646. var chart = window.acquireChart({}, {
  647. canvas: {
  648. height: 200,
  649. width: 200,
  650. style: 'height: 400px; width: 400px;'
  651. }
  652. });
  653. helpers.retinaScale(chart, true);
  654. var canvas = chart.canvas;
  655. expect(canvas.style.height).toBe('400px');
  656. expect(canvas.style.width).toBe('400px');
  657. });
  658. describe('Color helper', function() {
  659. function isColorInstance(obj) {
  660. return typeof obj === 'object' && obj.hasOwnProperty('values') && obj.values.hasOwnProperty('rgb');
  661. }
  662. it('should return a color when called with a color', function() {
  663. expect(isColorInstance(helpers.color('rgb(1, 2, 3)'))).toBe(true);
  664. });
  665. it('should return a color when called with a CanvasGradient instance', function() {
  666. var context = document.createElement('canvas').getContext('2d');
  667. var gradient = context.createLinearGradient(0, 1, 2, 3);
  668. expect(isColorInstance(helpers.color(gradient))).toBe(true);
  669. });
  670. });
  671. describe('Background hover color helper', function() {
  672. it('should return a CanvasPattern when called with a CanvasPattern', function(done) {
  673. var dots = new Image();
  674. dots.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAAD1BMVEUAAAD///////////////+PQt5oAAAABXRSTlMAHlFhZsfk/BEAAAAqSURBVHgBY2BgZGJmYmSAAUYWEIDzmcBcJhiXGcxlRpPFrhdmMiqgvX0AcGIBEUAo6UAAAAAASUVORK5CYII=';
  675. dots.onload = function() {
  676. var chartContext = document.createElement('canvas').getContext('2d');
  677. var patternCanvas = document.createElement('canvas');
  678. var patternContext = patternCanvas.getContext('2d');
  679. var pattern = patternContext.createPattern(dots, 'repeat');
  680. patternContext.fillStyle = pattern;
  681. var backgroundColor = helpers.getHoverColor(chartContext.createPattern(patternCanvas, 'repeat'));
  682. expect(backgroundColor instanceof CanvasPattern).toBe(true);
  683. done();
  684. };
  685. });
  686. it('should return a modified version of color when called with a color', function() {
  687. var originalColorRGB = 'rgb(70, 191, 189)';
  688. expect(helpers.getHoverColor('#46BFBD')).not.toEqual(originalColorRGB);
  689. });
  690. });
  691. });