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.

195 lines
6.8 KiB

  1. import NodeBase from './NodeBase';
  2. /**
  3. * NOTE: This is a bad base class
  4. *
  5. * Child classes are:
  6. *
  7. * Image - uses *only* image methods
  8. * Circle - uses *only* _drawRawCircle
  9. * CircleImage - uses all
  10. *
  11. * TODO: Refactor, move _drawRawCircle to different module, derive Circle from NodeBase
  12. * Rename this to ImageBase
  13. * Consolidate common code in Image and CircleImage to base class
  14. *
  15. * @class CircleImageBase
  16. * @extends NodeBase
  17. */
  18. class CircleImageBase extends NodeBase {
  19. /**
  20. *
  21. * @param {Object} options
  22. * @param {Object} body
  23. * @param {Label} labelModule
  24. * @constructor CircleImageBase
  25. */
  26. constructor(options, body, labelModule) {
  27. super(options, body, labelModule);
  28. this.labelOffset = 0;
  29. this.selected = false;
  30. }
  31. /**
  32. *
  33. * @param {Object} options
  34. * @param {Object} [imageObj]
  35. * @param {Object} [imageObjAlt]
  36. */
  37. setOptions(options, imageObj, imageObjAlt) {
  38. this.options = options;
  39. if (!(imageObj === undefined && imageObjAlt === undefined)) {
  40. this.setImages(imageObj, imageObjAlt);
  41. }
  42. }
  43. /**
  44. * Set the images for this node.
  45. *
  46. * The images can be updated after the initial setting of options;
  47. * therefore, this method needs to be reentrant.
  48. *
  49. * For correct working in error cases, it is necessary to properly set
  50. * field 'nodes.brokenImage' in the options.
  51. *
  52. * @param {Image} imageObj required; main image to show for this node
  53. * @param {Image|undefined} imageObjAlt optional; image to show when node is selected
  54. */
  55. setImages(imageObj, imageObjAlt) {
  56. if (imageObjAlt && this.selected) {
  57. this.imageObj = imageObjAlt;
  58. this.imageObjAlt = imageObj;
  59. } else {
  60. this.imageObj = imageObj;
  61. this.imageObjAlt = imageObjAlt;
  62. }
  63. }
  64. /**
  65. * Set selection and switch between the base and the selected image.
  66. *
  67. * Do the switch only if imageObjAlt exists.
  68. *
  69. * @param {Boolean} selected value of new selected state for current node
  70. */
  71. switchImages(selected) {
  72. var selection_changed = ((selected && !this.selected) || (!selected && this.selected));
  73. this.selected = selected; // Remember new selection
  74. if (this.imageObjAlt !== undefined && selection_changed) {
  75. let imageTmp = this.imageObj;
  76. this.imageObj = this.imageObjAlt;
  77. this.imageObjAlt = imageTmp;
  78. }
  79. }
  80. /**
  81. * Adjust the node dimensions for a loaded image.
  82. *
  83. * Pre: this.imageObj is valid
  84. */
  85. _resizeImage() {
  86. var width, height;
  87. if (this.options.shapeProperties.useImageSize === false) {
  88. // Use the size property
  89. var ratio_width = 1;
  90. var ratio_height = 1;
  91. // Only calculate the proper ratio if both width and height not zero
  92. if (this.imageObj.width && this.imageObj.height) {
  93. if (this.imageObj.width > this.imageObj.height) {
  94. ratio_width = this.imageObj.width / this.imageObj.height;
  95. }
  96. else {
  97. ratio_height = this.imageObj.height / this.imageObj.width;
  98. }
  99. }
  100. width = this.options.size * 2 * ratio_width;
  101. height = this.options.size * 2 * ratio_height;
  102. }
  103. else {
  104. // Use the image size
  105. width = this.imageObj.width;
  106. height = this.imageObj.height;
  107. }
  108. this.width = width;
  109. this.height = height;
  110. this.radius = 0.5 * this.width;
  111. }
  112. /**
  113. *
  114. * @param {CanvasRenderingContext2D} ctx
  115. * @param {number} x width
  116. * @param {number} y height
  117. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  118. * @private
  119. */
  120. _drawRawCircle(ctx, x, y, values) {
  121. this.initContextForDraw(ctx, values);
  122. ctx.circle(x, y, values.size);
  123. this.performFill(ctx, values);
  124. }
  125. /**
  126. *
  127. * @param {CanvasRenderingContext2D} ctx
  128. * @param {{toArrow: boolean, toArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), toArrowType: *, middleArrow: boolean, middleArrowScale: (number|allOptions.edges.arrows.middle.scaleFactor|{number}|Array), middleArrowType: (allOptions.edges.arrows.middle.type|{string}|string|*), fromArrow: boolean, fromArrowScale: (allOptions.edges.arrows.to.scaleFactor|{number}|allOptions.edges.arrows.middle.scaleFactor|allOptions.edges.arrows.from.scaleFactor|Array|number), fromArrowType: *, arrowStrikethrough: (*|boolean|allOptions.edges.arrowStrikethrough|{boolean}), color: undefined, inheritsColor: (string|string|string|allOptions.edges.color.inherit|{string, boolean}|Array|*), opacity: *, hidden: *, length: *, shadow: *, shadowColor: *, shadowSize: *, shadowX: *, shadowY: *, dashes: (*|boolean|Array|allOptions.edges.dashes|{boolean, array}), width: *}} values
  129. * @private
  130. */
  131. _drawImageAtPosition(ctx, values) {
  132. if (this.imageObj.width != 0) {
  133. // draw the image
  134. ctx.globalAlpha = 1.0;
  135. // draw shadow if enabled
  136. this.enableShadow(ctx, values);
  137. let factor = 1;
  138. if (this.options.shapeProperties.interpolation === true) {
  139. factor = (this.imageObj.width / this.width) / this.body.view.scale;
  140. }
  141. this.imageObj.drawImageAtPosition(ctx, factor, this.left, this.top, this.width, this.height);
  142. // disable shadows for other elements.
  143. this.disableShadow(ctx, values);
  144. }
  145. }
  146. /**
  147. *
  148. * @param {CanvasRenderingContext2D} ctx
  149. * @param {number} x width
  150. * @param {number} y height
  151. * @param {boolean} selected
  152. * @param {boolean} hover
  153. * @private
  154. */
  155. _drawImageLabel(ctx, x, y, selected, hover) {
  156. var yLabel;
  157. var offset = 0;
  158. if (this.height !== undefined) {
  159. offset = this.height * 0.5;
  160. var labelDimensions = this.labelModule.getTextSize(ctx, selected, hover);
  161. if (labelDimensions.lineCount >= 1) {
  162. offset += labelDimensions.height / 2;
  163. }
  164. }
  165. yLabel = y + offset;
  166. if (this.options.label) {
  167. this.labelOffset = offset;
  168. }
  169. this.labelModule.draw(ctx, x, yLabel, selected, hover, 'hanging');
  170. }
  171. }
  172. export default CircleImageBase;