docs: function () {
              var i, lastZoomLevel,
                  zoomLevels = this.config.zoomLevels.slice() || [1],
                  auto = this.calculateZoomValue(Crocodoc.ZOOM_AUTO),
                  fitWidth = this.calculateZoomValue(Crocodoc.ZOOM_FIT_WIDTH),
                  fitHeight = this.calculateZoomValue(Crocodoc.ZOOM_FIT_HEIGHT),
                  presets = [fitWidth, fitHeight];
  
              // update min and max zoom before adding presets into the mix
              // because presets should not be able to override min/max zoom
              this.state.minZoom = this.config.minZoom || zoomLevels[0];
              this.state.maxZoom = this.config.maxZoom || zoomLevels[zoomLevels.length - 1];
  
              // if auto is not the same as fitWidth or fitHeight,
              // add it as a possible next zoom
              if (auto !== fitWidth && auto !== fitHeight) {
                  presets.push(auto);
              }
  
              // add auto-zoom levels and sort
              zoomLevels = zoomLevels.concat(presets);
              zoomLevels.sort(function sortZoomLevels(a, b){
                  return a - b;
              });
  
              this.zoomLevels = [];
  
              /**
               * Return true if we should use this zoom level
               * @param   {number} zoomLevel The zoom level to consider
               * @returns {boolean}          True if we should keep this level
               * @private
               */
              function shouldUseZoomLevel(zoomLevel) {
                  var similarity = lastZoomLevel / zoomLevel;
                  // remove duplicates
                  if (zoomLevel === lastZoomLevel) {
                      return false;
                  }
                  // keep anything that is within the similarity threshold
                  if (similarity < ZOOM_LEVEL_SIMILARITY_THRESHOLD) {
                      return true;
                  }
                  // check if it's a preset
                  if (util.inArray(zoomLevel, presets) > -1) {
                      // keep presets if they are within a higher threshold
                      if (similarity < ZOOM_LEVEL_PRESETS_SIMILARITY_THRESHOLD) {
                          return true;
                      }
                  }
                  return false;
              }
  
              // remove duplicates from sorted list, and remove unnecessary levels
              // @NOTE: some zoom levels end up being very close to the built-in
              // presets (fit-width/fit-height/auto), which makes zooming previous
              // or next level kind of annoying when the zoom level barely changes.
              // This fixes that by applying a threshold to the zoom levels to
              // each preset, and removing the non-preset version if the
              // ratio is below the threshold.
              lastZoomLevel = 0;
              for (i = 0; i < zoomLevels.length; ++i) {
                  if (shouldUseZoomLevel(zoomLevels[i])) {
                      lastZoomLevel = zoomLevels[i];
                      this.zoomLevels.push(lastZoomLevel);
                  }
              }
          }