vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
7.0 KiB

  1. var util = require('../../util');
  2. var DOMutil = require('../../DOMutil');
  3. var Component = require('./Component');
  4. /**
  5. * Legend for Graph2d
  6. *
  7. * @param {vis.Graph2d.body} body
  8. * @param {vis.Graph2d.options} options
  9. * @param {number} side
  10. * @param {vis.LineGraph.options} linegraphOptions
  11. * @constructor Legend
  12. * @extends Component
  13. */
  14. function Legend(body, options, side, linegraphOptions) {
  15. this.body = body;
  16. this.defaultOptions = {
  17. enabled: false,
  18. icons: true,
  19. iconSize: 20,
  20. iconSpacing: 6,
  21. left: {
  22. visible: true,
  23. position: 'top-left' // top/bottom - left,center,right
  24. },
  25. right: {
  26. visible: true,
  27. position: 'top-right' // top/bottom - left,center,right
  28. }
  29. };
  30. this.side = side;
  31. this.options = util.extend({}, this.defaultOptions);
  32. this.linegraphOptions = linegraphOptions;
  33. this.svgElements = {};
  34. this.dom = {};
  35. this.groups = {};
  36. this.amountOfGroups = 0;
  37. this._create();
  38. this.framework = {svg: this.svg, svgElements: this.svgElements, options: this.options, groups: this.groups};
  39. this.setOptions(options);
  40. }
  41. Legend.prototype = new Component();
  42. Legend.prototype.clear = function() {
  43. this.groups = {};
  44. this.amountOfGroups = 0;
  45. };
  46. Legend.prototype.addGroup = function(label, graphOptions) {
  47. // Include a group only if the group option 'excludeFromLegend: false' is not set.
  48. if (graphOptions.options.excludeFromLegend != true) {
  49. if (!this.groups.hasOwnProperty(label)) {
  50. this.groups[label] = graphOptions;
  51. }
  52. this.amountOfGroups += 1;
  53. }
  54. };
  55. Legend.prototype.updateGroup = function(label, graphOptions) {
  56. this.groups[label] = graphOptions;
  57. };
  58. Legend.prototype.removeGroup = function(label) {
  59. if (this.groups.hasOwnProperty(label)) {
  60. delete this.groups[label];
  61. this.amountOfGroups -= 1;
  62. }
  63. };
  64. Legend.prototype._create = function() {
  65. this.dom.frame = document.createElement('div');
  66. this.dom.frame.className = 'vis-legend';
  67. this.dom.frame.style.position = "absolute";
  68. this.dom.frame.style.top = "10px";
  69. this.dom.frame.style.display = "block";
  70. this.dom.textArea = document.createElement('div');
  71. this.dom.textArea.className = 'vis-legend-text';
  72. this.dom.textArea.style.position = "relative";
  73. this.dom.textArea.style.top = "0px";
  74. this.svg = document.createElementNS('http://www.w3.org/2000/svg',"svg");
  75. this.svg.style.position = 'absolute';
  76. this.svg.style.top = 0 +'px';
  77. this.svg.style.width = this.options.iconSize + 5 + 'px';
  78. this.svg.style.height = '100%';
  79. this.dom.frame.appendChild(this.svg);
  80. this.dom.frame.appendChild(this.dom.textArea);
  81. };
  82. /**
  83. * Hide the component from the DOM
  84. */
  85. Legend.prototype.hide = function() {
  86. // remove the frame containing the items
  87. if (this.dom.frame.parentNode) {
  88. this.dom.frame.parentNode.removeChild(this.dom.frame);
  89. }
  90. };
  91. /**
  92. * Show the component in the DOM (when not already visible).
  93. */
  94. Legend.prototype.show = function() {
  95. // show frame containing the items
  96. if (!this.dom.frame.parentNode) {
  97. this.body.dom.center.appendChild(this.dom.frame);
  98. }
  99. };
  100. Legend.prototype.setOptions = function(options) {
  101. var fields = ['enabled','orientation','icons','left','right'];
  102. util.selectiveDeepExtend(fields, this.options, options);
  103. };
  104. Legend.prototype.redraw = function() {
  105. var activeGroups = 0;
  106. var groupArray = Object.keys(this.groups);
  107. groupArray.sort(function (a,b) {
  108. return (a < b ? -1 : 1);
  109. })
  110. for (var i = 0; i < groupArray.length; i++) {
  111. var groupId = groupArray[i];
  112. if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
  113. activeGroups++;
  114. }
  115. }
  116. if (this.options[this.side].visible == false || this.amountOfGroups == 0 || this.options.enabled == false || activeGroups == 0) {
  117. this.hide();
  118. }
  119. else {
  120. this.show();
  121. if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'bottom-left') {
  122. this.dom.frame.style.left = '4px';
  123. this.dom.frame.style.textAlign = "left";
  124. this.dom.textArea.style.textAlign = "left";
  125. this.dom.textArea.style.left = (this.options.iconSize + 15) + 'px';
  126. this.dom.textArea.style.right = '';
  127. this.svg.style.left = 0 +'px';
  128. this.svg.style.right = '';
  129. }
  130. else {
  131. this.dom.frame.style.right = '4px';
  132. this.dom.frame.style.textAlign = "right";
  133. this.dom.textArea.style.textAlign = "right";
  134. this.dom.textArea.style.right = (this.options.iconSize + 15) + 'px';
  135. this.dom.textArea.style.left = '';
  136. this.svg.style.right = 0 +'px';
  137. this.svg.style.left = '';
  138. }
  139. if (this.options[this.side].position == 'top-left' || this.options[this.side].position == 'top-right') {
  140. this.dom.frame.style.top = 4 - Number(this.body.dom.center.style.top.replace("px","")) + 'px';
  141. this.dom.frame.style.bottom = '';
  142. }
  143. else {
  144. var scrollableHeight = this.body.domProps.center.height - this.body.domProps.centerContainer.height;
  145. this.dom.frame.style.bottom = 4 + scrollableHeight + Number(this.body.dom.center.style.top.replace("px","")) + 'px';
  146. this.dom.frame.style.top = '';
  147. }
  148. if (this.options.icons == false) {
  149. this.dom.frame.style.width = this.dom.textArea.offsetWidth + 10 + 'px';
  150. this.dom.textArea.style.right = '';
  151. this.dom.textArea.style.left = '';
  152. this.svg.style.width = '0px';
  153. }
  154. else {
  155. this.dom.frame.style.width = this.options.iconSize + 15 + this.dom.textArea.offsetWidth + 10 + 'px'
  156. this.drawLegendIcons();
  157. }
  158. var content = '';
  159. for (i = 0; i < groupArray.length; i++) {
  160. groupId = groupArray[i];
  161. if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
  162. content += this.groups[groupId].content + '<br />';
  163. }
  164. }
  165. this.dom.textArea.innerHTML = content;
  166. this.dom.textArea.style.lineHeight = ((0.75 * this.options.iconSize) + this.options.iconSpacing) + 'px';
  167. }
  168. };
  169. Legend.prototype.drawLegendIcons = function() {
  170. if (this.dom.frame.parentNode) {
  171. var groupArray = Object.keys(this.groups);
  172. groupArray.sort(function (a,b) {
  173. return (a < b ? -1 : 1);
  174. });
  175. // this resets the elements so the order is maintained
  176. DOMutil.resetElements(this.svgElements);
  177. var padding = window.getComputedStyle(this.dom.frame).paddingTop;
  178. var iconOffset = Number(padding.replace('px',''));
  179. var x = iconOffset;
  180. var iconWidth = this.options.iconSize;
  181. var iconHeight = 0.75 * this.options.iconSize;
  182. var y = iconOffset + 0.5 * iconHeight + 3;
  183. this.svg.style.width = iconWidth + 5 + iconOffset + 'px';
  184. for (var i = 0; i < groupArray.length; i++) {
  185. var groupId = groupArray[i];
  186. if (this.groups[groupId].visible == true && (this.linegraphOptions.visibility[groupId] === undefined || this.linegraphOptions.visibility[groupId] == true)) {
  187. this.groups[groupId].getLegend(iconWidth, iconHeight, this.framework, x, y);
  188. y += iconHeight + this.options.iconSpacing;
  189. }
  190. }
  191. }
  192. };
  193. module.exports = Legend;