All files / src/components/Canvas CanvasCache.js

87.5% Statements 21/24
88.89% Branches 8/9
80% Functions 4/5
91.3% Lines 21/23
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89                                              32x 32x                       12261x 11933x   328x         328x 328x       328x 328x 328x 328x   328x 328x                           54x 38x 38x 38x   16x             74x 74x 74x          
/**
* Copyright 2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
 
import shallowEqual from '../../utils/shallowEqual';
import {
  minBy
} from 'lodash-es';
 
/**
 * A simple, in-memory cache for Canvas tiles outside of the DOM.
 * Gets automatically invalidated when called with different widths.
 * If `maxElements` are exceed, the oldest element (by insertion time) will be
 * removed from the cache.
 *
 * @param {Number} maxElements Maximal elements to keep in the cache (default: 200)
 */
class CanvasCache {
  constructor({maxElements} = {}) {
    this.maxElements = maxElements || 200;
    this.invalidate();
  }
 
  /**
   * Creates a canvas element outside of the DOM that can be used for caching.
   * @param {string} key Unique cache key of the element
   * @param {Number} tileWidth Width of the to be created canvas
   * @param {Number} tileWidth Width of the to be created canvas
   * @param {function} create Callback to be called if for the given `key` to canvas exists in the cache
   */
  createTile({key, tileWidth, tileHeight, create}) {
    // check if cache needs to be regenerated
    if (key in this.cache) {
      return this.cache[key].value;
    }
    Iif (this.cachedElements >= this.maxElements) {
      // purge oldest key from cache if maxSize is reached
      const oldestKey = minBy(Object.keys(this.cache), k => this.cache[k].insertionTime);
      delete this.cache[oldestKey];
    }
    const canvas = document.createElement("canvas");
    this.cache[key] = {
      value: canvas,
      insertionTime: Date.now(),
    };
    canvas.width = tileWidth;
    canvas.height = tileHeight;
    const ctx = canvas.getContext('2d');
    this.cachedElements++;
 
    create({canvas: ctx});
    return canvas;
  }
 
  /**
   * Checks whether the tile specification has changed and the cache needs
   * to be refreshed.
   * Pass in an object of all the properties that would result in the cache to be refreshed
   * Like React.PureComponents the passed-in properties are compared by their
   * shallow equality.
   *
   * @param {object} spec Object of all parameters that depend on this cache
   * Returns: `true` when the cache has been invalidated
   */
  updateTileSpecs(spec) {
    if (!shallowEqual(spec, this.spec)) {
      this.invalidate();
      this.spec = spec;
      return true;
    }
    return false;
  }
 
  /**
   * Invalidates the entire cache and removed all elements.
   */
  invalidate() {
    this.cache = {};
    this.spec = {};
    this.cachedElements = 0;
  }
}
 
export default CanvasCache;