# all files / ol/style/ atlasmanager.js

96.36% Statements 53/55
91.18% Branches 31/34
100% Functions 6/6
96.36% Lines 53/55

    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
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    2201×

    1×
    1×

    1×

    25×

    25×

    25×

    25×

    25×

    25×

    25×

    1×

    39×

    39×
    2×

    37×

    37×

    1×
    76×
    76×
    76×
    76×
    76×
    74×

    2×

    1×
    93×

    1×

    57×

    1×

    56×

    56×

    56×

    56×

    56×

    1×

    112×
    112×
    112×
    124×
    124×
    124×
    112×
    12×

    10×
    10×
    5×
    5×

    5×
    5×

    10×
    10×

    10×

     goog.provide('ol.style.AtlasManager');

    goog.require('ol');
    goog.require('ol.style.Atlas');

    /**
     * Manages the creation of image atlases.
     *
     * Images added to this manager will be inserted into an atlas, which
     * will be used for rendering.
     * The `size` given in the constructor is the size for the first
     * atlas. After that, when new atlases are created, they will have
     * twice the size as the latest atlas (until `maxSize` is reached).
     *
     * If an application uses many images or very large images, it is recommended
     * to set a higher `size` value to avoid the creation of too many atlases.
     *
     * @constructor
     * @struct
     * @api
     * @param {olx.style.AtlasManagerOptions=} opt_options Options.
     */
    ol.style.AtlasManager = function(opt_options) {

      var options = opt_options || {};

      /**
       * The size in pixels of the latest atlas image.
       * @private
       * @type {number}
       */
      this.currentSize_ = options.initialSize !== undefined ?
        options.initialSize : ol.INITIAL_ATLAS_SIZE;

      /**
       * The maximum size in pixels of atlas images.
       * @private
       * @type {number}
       */
      this.maxSize_ = options.maxSize !== undefined ?
        options.maxSize : ol.MAX_ATLAS_SIZE != -1 ?
          ol.MAX_ATLAS_SIZE : ol.WEBGL_MAX_TEXTURE_SIZE !== undefined ?
            ol.WEBGL_MAX_TEXTURE_SIZE : 2048;

      /**
       * The size in pixels between images.
       * @private
       * @type {number}
       */
      this.space_ = options.space !== undefined ? options.space : 1;

      /**
       * @private
       * @type {Array.<ol.style.Atlas>}
       */
      this.atlases_ = [new ol.style.Atlas(this.currentSize_, this.space_)];

      /**
       * The size in pixels of the latest atlas image for hit-detection images.
       * @private
       * @type {number}
       */
      this.currentHitSize_ = this.currentSize_;

      /**
       * @private
       * @type {Array.<ol.style.Atlas>}
       */
      this.hitAtlases_ = [new ol.style.Atlas(this.currentHitSize_, this.space_)];
    };

    /**
     * @param {string} id The identifier of the entry to check.
     * @return {?ol.AtlasManagerInfo} The position and atlas image for the
     *    entry, or `null` if the entry is not part of the atlas manager.
     */
    ol.style.AtlasManager.prototype.getInfo = function(id) {
      /** @type {?ol.AtlasInfo} */
      var info = this.getInfo_(this.atlases_, id);

      if (!info) {
        return null;
      }
      var hitInfo = /** @type {ol.AtlasInfo} */ (this.getInfo_(this.hitAtlases_, id));

      return this.mergeInfos_(info, hitInfo);
    };

    /**
     * @private
     * @param {Array.<ol.style.Atlas>} atlases The atlases to search.
     * @param {string} id The identifier of the entry to check.
     * @return {?ol.AtlasInfo} The position and atlas image for the entry,
     *    or `null` if the entry is not part of the atlases.
     */
    ol.style.AtlasManager.prototype.getInfo_ = function(atlases, id) {
      var atlas, info, i, ii;
      for (i = 0, ii = atlases.length; i < ii; ++i) {
        atlas = atlases[i];
        info = atlas.get(id);
        if (info) {
          return info;
        }
      }
      return null;
    };

    /**
     * @private
     * @param {ol.AtlasInfo} info The info for the real image.
     * @param {ol.AtlasInfo} hitInfo The info for the hit-detection
     *    image.
     * @return {?ol.AtlasManagerInfo} The position and atlas image for the
     *    entry, or `null` if the entry is not part of the atlases.
     */
    ol.style.AtlasManager.prototype.mergeInfos_ = function(info, hitInfo) {
      return /** @type {ol.AtlasManagerInfo} */ ({
        offsetX: info.offsetX,
        offsetY: info.offsetY,
        image: info.image,
        hitImage: hitInfo.image
      });
    };

    /**
     * Add an image to the atlas manager.
     *
     * If an entry for the given id already exists, the entry will
     * be overridden (but the space on the atlas graphic will not be freed).
     *
     * If `renderHitCallback` is provided, the image (or the hit-detection version
     * of the image) will be rendered into a separate hit-detection atlas image.
     *
     * @param {string} id The identifier of the entry to add.
     * @param {number} width The width.
     * @param {number} height The height.
     * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
     *    Called to render the new image onto an atlas image.
     * @param {function(CanvasRenderingContext2D, number, number)=}
     *    opt_renderHitCallback Called to render a hit-detection image onto a hit
     *    detection atlas image.
     * @param {Object=} opt_this Value to use as `this` when executing
     *    `renderCallback` and `renderHitCallback`.
     * @return {?ol.AtlasManagerInfo}  The position and atlas image for the
     *    entry, or `null` if the image is too big.
     */
    ol.style.AtlasManager.prototype.add = function(id, width, height,
        renderCallback, opt_renderHitCallback, opt_this) {
      if (width + this.space_ > this.maxSize_ ||
          height + this.space_ > this.maxSize_) {
        return null;
      }

      /** @type {?ol.AtlasInfo} */
      var info = this.add_(false,
          id, width, height, renderCallback, opt_this);
      Iif (!info) {
        return null;
      }

      // even if no hit-detection entry is requested, we insert a fake entry into
      // the hit-detection atlas, to make sure that the offset is the same for
      // the original image and the hit-detection image.
      var renderHitCallback = opt_renderHitCallback !== undefined ?
        opt_renderHitCallback : ol.nullFunction;

      var hitInfo = /** @type {ol.AtlasInfo} */ (this.add_(true,
          id, width, height, renderHitCallback, opt_this));

      return this.mergeInfos_(info, hitInfo);
    };

    /**
     * @private
     * @param {boolean} isHitAtlas If the hit-detection atlases are used.
     * @param {string} id The identifier of the entry to add.
     * @param {number} width The width.
     * @param {number} height The height.
     * @param {function(CanvasRenderingContext2D, number, number)} renderCallback
     *    Called to render the new image onto an atlas image.
     * @param {Object=} opt_this Value to use as `this` when executing
     *    `renderCallback` and `renderHitCallback`.
     * @return {?ol.AtlasInfo}  The position and atlas image for the entry,
     *    or `null` if the image is too big.
     */
    ol.style.AtlasManager.prototype.add_ = function(isHitAtlas, id, width, height,
        renderCallback, opt_this) {
      var atlases = (isHitAtlas) ? this.hitAtlases_ : this.atlases_;
      var atlas, info, i, ii;
      for (i = 0, ii = atlases.length; i < ii; ++i) {
        atlas = atlases[i];
        info = atlas.add(id, width, height, renderCallback, opt_this);
        if (info) {
          return info;
        } else if (!info && i === ii - 1) {
          // the entry could not be added to one of the existing atlases,
          // create a new atlas that is twice as big and try to add to this one.
          var size;
          if (isHitAtlas) {
            size = Math.min(this.currentHitSize_ * 2, this.maxSize_);
            this.currentHitSize_ = size;
          } else {
            size = Math.min(this.currentSize_ * 2, this.maxSize_);
            this.currentSize_ = size;
          }
          atlas = new ol.style.Atlas(size, this.space_);
          atlases.push(atlas);
          // run the loop another time
          ++ii;
        }
      }
      return null;
    };