b14b8e76a02ebdd96ddee7c6505bdc9ec11c480ab7bbbe827161eb3e3631690bc5694131cdcd0249e46336c00abb773b04ae7b9dda65dc340dd3885736a8d4 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import LRU from '../../core/LRU';
  2. import { platformApi } from '../../core/platform';
  3. import { ImageLike } from '../../core/types';
  4. const globalImageCache = new LRU<CachedImageObj>(50);
  5. type PendingWrap = {
  6. hostEl: {dirty: () => void}
  7. cb: (image: ImageLike, payload: any) => void
  8. cbPayload: any
  9. }
  10. type CachedImageObj = {
  11. image: ImageLike
  12. pending: PendingWrap[]
  13. }
  14. export function findExistImage(newImageOrSrc: string | ImageLike): ImageLike {
  15. if (typeof newImageOrSrc === 'string') {
  16. const cachedImgObj = globalImageCache.get(newImageOrSrc);
  17. return cachedImgObj && cachedImgObj.image;
  18. }
  19. else {
  20. return newImageOrSrc;
  21. }
  22. }
  23. /**
  24. * Caution: User should cache loaded images, but not just count on LRU.
  25. * Consider if required images more than LRU size, will dead loop occur?
  26. *
  27. * @param newImageOrSrc
  28. * @param image Existent image.
  29. * @param hostEl For calling `dirty`.
  30. * @param onload params: (image, cbPayload)
  31. * @param cbPayload Payload on cb calling.
  32. * @return image
  33. */
  34. export function createOrUpdateImage<T>(
  35. newImageOrSrc: string | ImageLike,
  36. image: ImageLike,
  37. hostEl: { dirty: () => void },
  38. onload?: (image: ImageLike, payload: T) => void,
  39. cbPayload?: T
  40. ) {
  41. if (!newImageOrSrc) {
  42. return image;
  43. }
  44. else if (typeof newImageOrSrc === 'string') {
  45. // Image should not be loaded repeatly.
  46. if ((image && (image as any).__zrImageSrc === newImageOrSrc) || !hostEl) {
  47. return image;
  48. }
  49. // Only when there is no existent image or existent image src
  50. // is different, this method is responsible for load.
  51. const cachedImgObj = globalImageCache.get(newImageOrSrc);
  52. const pendingWrap = {hostEl: hostEl, cb: onload, cbPayload: cbPayload};
  53. if (cachedImgObj) {
  54. image = cachedImgObj.image;
  55. !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);
  56. }
  57. else {
  58. image = platformApi.loadImage(
  59. newImageOrSrc, imageOnLoad, imageOnLoad
  60. );
  61. (image as any).__zrImageSrc = newImageOrSrc;
  62. globalImageCache.put(
  63. newImageOrSrc,
  64. (image as any).__cachedImgObj = {
  65. image: image,
  66. pending: [pendingWrap]
  67. }
  68. );
  69. }
  70. return image;
  71. }
  72. // newImageOrSrc is an HTMLImageElement or HTMLCanvasElement or Canvas
  73. else {
  74. return newImageOrSrc;
  75. }
  76. }
  77. function imageOnLoad(this: any) {
  78. const cachedImgObj = this.__cachedImgObj;
  79. this.onload = this.onerror = this.__cachedImgObj = null;
  80. for (let i = 0; i < cachedImgObj.pending.length; i++) {
  81. const pendingWrap = cachedImgObj.pending[i];
  82. const cb = pendingWrap.cb;
  83. cb && cb(this, pendingWrap.cbPayload);
  84. pendingWrap.hostEl.dirty();
  85. }
  86. cachedImgObj.pending.length = 0;
  87. }
  88. export function isImageReady(image: ImageLike) {
  89. return image && image.width && image.height;
  90. }