background.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  2. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  3. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  4. else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  5. return c > 3 && r && Object.defineProperty(target, key, r), r;
  6. };
  7. import { ObjectExt } from '@antv/x6-common';
  8. import { Rectangle } from '@antv/x6-geometry';
  9. import { Background } from '../registry';
  10. import { Base } from './base';
  11. export class BackgroundManager extends Base {
  12. get elem() {
  13. return this.view.background;
  14. }
  15. init() {
  16. this.startListening();
  17. if (this.options.background) {
  18. this.draw(this.options.background);
  19. }
  20. }
  21. startListening() {
  22. this.graph.on('scale', this.update, this);
  23. this.graph.on('translate', this.update, this);
  24. }
  25. stopListening() {
  26. this.graph.off('scale', this.update, this);
  27. this.graph.off('translate', this.update, this);
  28. }
  29. updateBackgroundImage(options = {}) {
  30. let backgroundSize = options.size || 'auto auto';
  31. let backgroundPosition = options.position || 'center';
  32. const scale = this.graph.transform.getScale();
  33. const ts = this.graph.translate();
  34. // backgroundPosition
  35. if (typeof backgroundPosition === 'object') {
  36. const x = ts.tx + scale.sx * (backgroundPosition.x || 0);
  37. const y = ts.ty + scale.sy * (backgroundPosition.y || 0);
  38. backgroundPosition = `${x}px ${y}px`;
  39. }
  40. // backgroundSize
  41. if (typeof backgroundSize === 'object') {
  42. backgroundSize = Rectangle.fromSize(backgroundSize).scale(scale.sx, scale.sy);
  43. backgroundSize = `${backgroundSize.width}px ${backgroundSize.height}px`;
  44. }
  45. this.elem.style.backgroundSize = backgroundSize;
  46. this.elem.style.backgroundPosition = backgroundPosition;
  47. }
  48. drawBackgroundImage(img, options = {}) {
  49. if (!(img instanceof HTMLImageElement)) {
  50. this.elem.style.backgroundImage = '';
  51. return;
  52. }
  53. // draw multiple times to show the last image
  54. const cache = this.optionsCache;
  55. if (cache && cache.image !== options.image) {
  56. return;
  57. }
  58. let uri;
  59. const opacity = options.opacity;
  60. const backgroundSize = options.size;
  61. let backgroundRepeat = options.repeat || 'no-repeat';
  62. const pattern = Background.registry.get(backgroundRepeat);
  63. if (typeof pattern === 'function') {
  64. const quality = options.quality || 1;
  65. img.width *= quality;
  66. img.height *= quality;
  67. const canvas = pattern(img, options);
  68. if (!(canvas instanceof HTMLCanvasElement)) {
  69. throw new Error('Background pattern must return an HTML Canvas instance');
  70. }
  71. uri = canvas.toDataURL('image/png');
  72. // `repeat` was changed in pattern function
  73. if (options.repeat && backgroundRepeat !== options.repeat) {
  74. backgroundRepeat = options.repeat;
  75. }
  76. else {
  77. backgroundRepeat = 'repeat';
  78. }
  79. if (typeof backgroundSize === 'object') {
  80. // recalculate the tile size if an object passed in
  81. backgroundSize.width *= canvas.width / img.width;
  82. backgroundSize.height *= canvas.height / img.height;
  83. }
  84. else if (backgroundSize === undefined) {
  85. // calcule the tile size if no provided
  86. options.size = {
  87. width: canvas.width / quality,
  88. height: canvas.height / quality,
  89. };
  90. }
  91. }
  92. else {
  93. uri = img.src;
  94. if (backgroundSize === undefined) {
  95. options.size = {
  96. width: img.width,
  97. height: img.height,
  98. };
  99. }
  100. }
  101. if (cache != null &&
  102. typeof options.size === 'object' &&
  103. options.image === cache.image &&
  104. options.repeat === cache.repeat &&
  105. options.quality ===
  106. cache.quality) {
  107. cache.size = ObjectExt.clone(options.size);
  108. }
  109. const style = this.elem.style;
  110. style.backgroundImage = `url(${uri})`;
  111. style.backgroundRepeat = backgroundRepeat;
  112. style.opacity = opacity == null || opacity >= 1 ? '' : `${opacity}`;
  113. this.updateBackgroundImage(options);
  114. }
  115. updateBackgroundColor(color) {
  116. this.elem.style.backgroundColor = color || '';
  117. }
  118. updateBackgroundOptions(options) {
  119. this.graph.options.background = options;
  120. }
  121. update() {
  122. if (this.optionsCache) {
  123. this.updateBackgroundImage(this.optionsCache);
  124. }
  125. }
  126. draw(options) {
  127. const opts = options || {};
  128. this.updateBackgroundOptions(options);
  129. this.updateBackgroundColor(opts.color);
  130. if (opts.image) {
  131. this.optionsCache = ObjectExt.clone(opts);
  132. const img = document.createElement('img');
  133. img.onload = () => this.drawBackgroundImage(img, options);
  134. img.setAttribute('crossorigin', 'anonymous');
  135. img.src = opts.image;
  136. }
  137. else {
  138. this.drawBackgroundImage(null);
  139. this.optionsCache = null;
  140. }
  141. }
  142. clear() {
  143. this.draw();
  144. }
  145. dispose() {
  146. this.clear();
  147. this.stopListening();
  148. }
  149. }
  150. __decorate([
  151. Base.dispose()
  152. ], BackgroundManager.prototype, "dispose", null);
  153. //# sourceMappingURL=background.js.map