chartist-plugin-tooltip.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /**
  2. * Chartist.js plugin to display a data label on top of the points in a line chart.
  3. *
  4. */
  5. /* global Chartist */
  6. (function (window, document, Chartist) {
  7. 'use strict';
  8. var defaultOptions = {
  9. currency: undefined,
  10. currencyFormatCallback: undefined,
  11. tooltipOffset: {
  12. x: 0,
  13. y: -20
  14. },
  15. anchorToPoint: false,
  16. appendToBody: false,
  17. class: undefined,
  18. pointClass: 'ct-point'
  19. };
  20. Chartist.plugins = Chartist.plugins || {};
  21. Chartist.plugins.tooltip = function (options) {
  22. options = Chartist.extend({}, defaultOptions, options);
  23. return function tooltip(chart) {
  24. var tooltipSelector = options.pointClass;
  25. if (chart instanceof Chartist.Bar) {
  26. tooltipSelector = 'ct-bar';
  27. } else if (chart instanceof Chartist.Pie) {
  28. // Added support for donut graph
  29. if (chart.options.donut) {
  30. tooltipSelector = 'ct-slice-donut';
  31. } else {
  32. tooltipSelector = 'ct-slice-pie';
  33. }
  34. }
  35. var $chart = chart.container;
  36. var $toolTip = $chart.querySelector('.chartist-tooltip');
  37. if (!$toolTip) {
  38. $toolTip = document.createElement('div');
  39. $toolTip.className = (!options.class) ? 'chartist-tooltip' : 'chartist-tooltip ' + options.class;
  40. if (!options.appendToBody) {
  41. $chart.appendChild($toolTip);
  42. } else {
  43. document.body.appendChild($toolTip);
  44. }
  45. }
  46. var height = $toolTip.offsetHeight;
  47. var width = $toolTip.offsetWidth;
  48. hide($toolTip);
  49. function on(event, selector, callback) {
  50. $chart.addEventListener(event, function (e) {
  51. if (!selector || hasClass(e.target, selector))
  52. callback(e);
  53. });
  54. }
  55. on('mouseover', tooltipSelector, function (event) {
  56. var $point = event.target;
  57. var tooltipText = '';
  58. var isPieChart = (chart instanceof Chartist.Pie) ? $point : $point.parentNode;
  59. var seriesName = (isPieChart) ? $point.parentNode.getAttribute('ct:meta') || $point.parentNode.getAttribute('ct:series-name') : '';
  60. var meta = $point.getAttribute('ct:meta') || seriesName || '';
  61. var hasMeta = !!meta;
  62. var value = $point.getAttribute('ct:value');
  63. if (options.transformTooltipTextFnc && typeof options.transformTooltipTextFnc === 'function') {
  64. value = options.transformTooltipTextFnc(value);
  65. }
  66. if (options.tooltipFnc && typeof options.tooltipFnc === 'function') {
  67. tooltipText = options.tooltipFnc(meta, value);
  68. } else {
  69. if (options.metaIsHTML) {
  70. var txt = document.createElement('textarea');
  71. txt.innerHTML = meta;
  72. meta = txt.value;
  73. }
  74. meta = '<span class="chartist-tooltip-meta">' + meta + '</span>';
  75. if (hasMeta) {
  76. tooltipText += meta + '<br>';
  77. } else {
  78. // For Pie Charts also take the labels into account
  79. // Could add support for more charts here as well!
  80. if (chart instanceof Chartist.Pie) {
  81. var label = next($point, 'ct-label');
  82. if (label) {
  83. tooltipText += text(label) + '<br>';
  84. }
  85. }
  86. }
  87. if (value) {
  88. if (options.currency) {
  89. if (options.currencyFormatCallback != undefined) {
  90. value = options.currencyFormatCallback(value, options);
  91. } else {
  92. value = options.currency + value.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, '$1,');
  93. }
  94. }
  95. value = '<span class="chartist-tooltip-value">' + value + '</span>';
  96. tooltipText += value;
  97. }
  98. }
  99. if(tooltipText) {
  100. $toolTip.innerHTML = tooltipText;
  101. setPosition(event);
  102. show($toolTip);
  103. // Remember height and width to avoid wrong position in IE
  104. height = $toolTip.offsetHeight;
  105. width = $toolTip.offsetWidth;
  106. }
  107. });
  108. on('mouseout', tooltipSelector, function () {
  109. hide($toolTip);
  110. });
  111. on('mousemove', null, function (event) {
  112. if (false === options.anchorToPoint)
  113. setPosition(event);
  114. });
  115. function setPosition(event) {
  116. height = height || $toolTip.offsetHeight;
  117. width = width || $toolTip.offsetWidth;
  118. var offsetX = - width / 2 + options.tooltipOffset.x
  119. var offsetY = - height + options.tooltipOffset.y;
  120. var anchorX, anchorY;
  121. if (!options.appendToBody) {
  122. var box = $chart.getBoundingClientRect();
  123. var left = event.pageX - box.left - window.pageXOffset ;
  124. var top = event.pageY - box.top - window.pageYOffset ;
  125. if (true === options.anchorToPoint && event.target.x2 && event.target.y2) {
  126. anchorX = parseInt(event.target.x2.baseVal.value);
  127. anchorY = parseInt(event.target.y2.baseVal.value);
  128. }
  129. $toolTip.style.top = (anchorY || top) + offsetY + 'px';
  130. $toolTip.style.left = (anchorX || left) + offsetX + 'px';
  131. } else {
  132. $toolTip.style.top = event.pageY + offsetY + 'px';
  133. $toolTip.style.left = event.pageX + offsetX + 'px';
  134. }
  135. }
  136. }
  137. };
  138. function show(element) {
  139. if(!hasClass(element, 'tooltip-show')) {
  140. element.className = element.className + ' tooltip-show';
  141. }
  142. }
  143. function hide(element) {
  144. var regex = new RegExp('tooltip-show' + '\\s*', 'gi');
  145. element.className = element.className.replace(regex, '').trim();
  146. }
  147. function hasClass(element, className) {
  148. return (' ' + element.getAttribute('class') + ' ').indexOf(' ' + className + ' ') > -1;
  149. }
  150. function next(element, className) {
  151. do {
  152. element = element.nextSibling;
  153. } while (element && !hasClass(element, className));
  154. return element;
  155. }
  156. function text(element) {
  157. return element.innerText || element.textContent;
  158. }
  159. } (window, document, Chartist));