Openlayers源码阅读(八):要素Feature渲染过程

上一篇中,主要理清了图层Layer的渲染方式, 其中,以IntermediateCanvas的图片渲染方式主要采用context.drawImage()的方式实现,而VectorLayer的渲染则不同,本文将进一步说明。

在后续的版本中,该部分做了调整,当整体上的思路基本一致。

导图

one
ol.render.canvas.ImageReplay
ol.render.canvas.LineStringReplay
ol.render.canvas.PolygonReplay
ol.render.canvas.TextReplay
ol.renderer.canvas.VectorLayer
ol.render.canvas.ReplayGroup
ol.renderer.vector
ol.render.canvas.Replay

开始前,请掌握矢量数据的特性、类型、结构等相关知识。

一、ol.renderer.canvas.VectorLayer

接着上一章的论述,在composeFrame() 、 prepareFrame()渲染中实现

1、composeFrame

prepareFrame
new ol.render.canvas.ReplayGroup
replayGroup.replay
/**
 * @inheritDoc
 */
ol.renderer.canvas.VectorLayer.prototype.composeFrame = function(frameState, layerState, context) {
    
    

 
  var replayGroup = this.replayGroup_;
  replayGroup.replay(replayContext, transform, rotation, skippedFeatureUids);
    
};

2、prepareFrame

prepareFrame
new ol.render.canvas.ReplayGroup
ol.renderer.vector.renderFeature
replayGroup.finish


ol.renderer.canvas.VectorLayer.prototype.prepareFrame = function(frameState, layerState) {
    
    

  ......
  // 初始化ReplayGroup
  var replayGroup = new ol.render.canvas.ReplayGroup(
      ol.renderer.vector.getTolerance(resolution, pixelRatio), extent, resolution,
      pixelRatio, vectorSource.getOverlaps(), this.declutterTree_, vectorLayer.getRenderBuffer());

  /**
   * @param {ol.Feature} feature Feature.
   * @this {ol.renderer.canvas.VectorLayer}
   */
  var renderFeature = function(feature) {
    
    
     ......
     var dirty = this.renderFeature(
          feature, resolution, pixelRatio, styles, replayGroup);
     
      ......
      
      renderFeature(features[i]);
      
      ......
   // 执行完成
  replayGroup.finish();
   
  ......
};

ol.renderer.canvas.VectorLayer.prototype.renderFeature = function(feature, resolution, pixelRatio, styles, replayGroup) {
    
    
  if (!styles) {
    
    
    return false;
  }
  var loading = false;
  if (Array.isArray(styles)) {
    
    
    for (var i = 0, ii = styles.length; i < ii; ++i) {
    
    
      loading = ol.renderer.vector.renderFeature(
          replayGroup, feature, styles[i],
          ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
          this.handleStyleImageChange_, this) || loading;
    }
  } else {
    
    
    loading = ol.renderer.vector.renderFeature(
        replayGroup, feature, styles,
        ol.renderer.vector.getSquaredTolerance(resolution, pixelRatio),
        this.handleStyleImageChange_, this);
  }
  return loading;
};

二、ol.renderer.vector

调用
simplifiedGeometry.getType
renderFeature
renderFeature_
GEOMETRY_RENDERERS_
renderPointGeometry_
renderLineStringGeometry_
renderPolygonGeometry_
renderLineStringGeometry_
renderMultiPointGeometry_
renderMultiLineStringGeometry_
renderMultiPolygonGeometry_
renderGeometryCollectionGeometry_
renderCircleGeometry_
/**
 * @param {ol.render.ReplayGroup} replayGroup Replay group.
 * @param {ol.Feature|ol.render.Feature} feature Feature.
 * @param {ol.style.Style} style Style.
 * @param {number} squaredTolerance Squared tolerance.
 * @param {function(this: T, ol.events.Event)} listener Listener function.
 * @param {T} thisArg Value to use as `this` when executing `listener`.
 * @return {boolean} `true` if style is loading.
 * @template T
 */
ol.renderer.vector.renderFeature = function(
    replayGroup, feature, style, squaredTolerance, listener, thisArg) {
    
    
  var loading = false;
  var imageStyle, imageState;
  imageStyle = style.getImage();
  if (imageStyle) {
    
    
    imageState = imageStyle.getImageState();
    if (imageState == ol.ImageState.LOADED ||
        imageState == ol.ImageState.ERROR) {
    
    
      imageStyle.unlistenImageChange(listener, thisArg);
    } else {
    
    
      if (imageState == ol.ImageState.IDLE) {
    
    
        imageStyle.load();
      }
      imageState = imageStyle.getImageState();
      imageStyle.listenImageChange(listener, thisArg);
      loading = true;
    }
  }
  ol.renderer.vector.renderFeature_(replayGroup, feature, style,
      squaredTolerance);

  return loading;
};

/**
 * @param {ol.render.ReplayGroup} replayGroup Replay group.
 * @param {ol.Feature|ol.render.Feature} feature Feature.
 * @param {ol.style.Style} style Style.
 * @param {number} squaredTolerance Squared tolerance.
 * @private
 */
ol.renderer.vector.renderFeature_ = function(
    replayGroup, feature, style, squaredTolerance) {
    
    
  var geometry = style.getGeometryFunction()(feature);
  if (!geometry) {
    
    
    return;
  }
  var simplifiedGeometry = geometry.getSimplifiedGeometry(squaredTolerance);
  var renderer = style.getRenderer();
  if (renderer) {
    
    
    ol.renderer.vector.renderGeometry_(replayGroup, simplifiedGeometry, style, feature);
  } else {
    
    
    var geometryRenderer =
        ol.renderer.vector.GEOMETRY_RENDERERS_[simplifiedGeometry.getType()];
    geometryRenderer(replayGroup, simplifiedGeometry, style, feature);
  }
};

/**
 * @const
 * @private
 * @type {Object.<ol.geom.GeometryType,
 *                function(ol.render.ReplayGroup, ol.geom.Geometry,
 *                         ol.style.Style, Object)>}
 */
ol.renderer.vector.GEOMETRY_RENDERERS_ = {
    
    
  'Point': ol.renderer.vector.renderPointGeometry_,
  'LineString': ol.renderer.vector.renderLineStringGeometry_,
  'Polygon': ol.renderer.vector.renderPolygonGeometry_,
  'MultiPoint': ol.renderer.vector.renderMultiPointGeometry_,
  'MultiLineString': ol.renderer.vector.renderMultiLineStringGeometry_,
  'MultiPolygon': ol.renderer.vector.renderMultiPolygonGeometry_,
  'GeometryCollection': ol.renderer.vector.renderGeometryCollectionGeometry_,
  'Circle': ol.renderer.vector.renderCircleGeometry_
};

三、ol.render.canvas.ReplayGroup

1、replay

ol.render.canvas.ReplayGroup.replay
new ol.render.canvas.ReplayGroup
ol.render.canvas.Replay.replay
/**
 * @param {CanvasRenderingContext2D} context Context.
 * @param {ol.Transform} transform Transform.
 * @param {number} viewRotation View rotation.
 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
 *     to skip.
 * @param {Array.<ol.render.ReplayType>=} opt_replayTypes Ordered replay types
 *     to replay. Default is {@link ol.render.replay.ORDER}
 * @param {Object.<string, ol.DeclutterGroup>=} opt_declutterReplays Declutter
 *     replays.
 */
ol.render.canvas.ReplayGroup.prototype.replay = function(context,
    transform, viewRotation, skippedFeaturesHash, opt_replayTypes, opt_declutterReplays) {
    
    

  /** @type {Array.<number>} */
  var zs = Object.keys(this.replaysByZIndex_).map(Number);
  zs.sort(ol.array.numberSafeCompareFunction);

  // setup clipping so that the parts of over-simplified geometries are not
  // visible outside the current extent when panning
  context.save();
  this.clip(context, transform);

  var replayTypes = opt_replayTypes ? opt_replayTypes : ol.render.replay.ORDER;
  var i, ii, j, jj, replays, replay;
  for (i = 0, ii = zs.length; i < ii; ++i) {
    
    
    var zIndexKey = zs[i].toString();
    replays = this.replaysByZIndex_[zIndexKey];
    for (j = 0, jj = replayTypes.length; j < jj; ++j) {
    
    
      var replayType = replayTypes[j];
      replay = replays[replayType];
      if (replay !== undefined) {
    
    
        if (opt_declutterReplays &&
            (replayType == ol.render.ReplayType.IMAGE || replayType == ol.render.ReplayType.TEXT)) {
    
    
          var declutter = opt_declutterReplays[zIndexKey];
          if (!declutter) {
    
    
            opt_declutterReplays[zIndexKey] = [replay, transform.slice(0)];
          } else {
    
    
            declutter.push(replay, transform.slice(0));
          }
        } else {
    
    
          replay.replay(context, transform, viewRotation, skippedFeaturesHash);
        }
      }
    }
  }

  context.restore();
};

2、finish

ol.render.canvas.ReplayGroup.finish
ol.render.canvas.Replay.finish
ol.render.canvas.PolygonReplay.finish
ol.render.canvas.ImageReplay.finish
ol.render.canvas.LineStringReplay.finish
ol.render.canvas.TextReplay.finish
/**
 * FIXME empty description for jsdoc
 */
ol.render.canvas.ReplayGroup.prototype.finish = function() {
    
    
  var zKey;
  for (zKey in this.replaysByZIndex_) {
    
    
    var replays = this.replaysByZIndex_[zKey];
    var replayKey;
    for (replayKey in replays) {
    
    
      replays[replayKey].finish();
      // replays[replayKey].finish() 实际上调用的是PolygonReplay等的finsih()
    }
  }
};

/**
 * @inheritDoc
 */
ol.render.canvas.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
    
    
  var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';
  var replays = this.replaysByZIndex_[zIndexKey];
  if (replays === undefined) {
    
    
    replays = {
    
    };
    this.replaysByZIndex_[zIndexKey] = replays;
  }
  var replay = replays[replayType];
  if (replay === undefined) {
    
    
    var Constructor = ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];
    replay = new Constructor(this.tolerance_, this.maxExtent_,
        this.resolution_, this.pixelRatio_, this.overlaps_, this.declutterTree_);
    replays[replayType] = replay;
  }
  return replay;
};

/**
 * @const
 * @private
 * @type {Object.<ol.render.ReplayType,
 *                function(new: ol.render.canvas.Replay, number, ol.Extent,
 *                number, number, boolean, Array.<ol.DeclutterGroup>)>}
 */
ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_ = {
    
    
  'Circle': ol.render.canvas.PolygonReplay,
  'Default': ol.render.canvas.Replay,
  'Image': ol.render.canvas.ImageReplay,
  'LineString': ol.render.canvas.LineStringReplay,
  'Polygon': ol.render.canvas.PolygonReplay,
  'Text': ol.render.canvas.TextReplay
};

四、ol.render.canvas.Replay

/**
 * @param {CanvasRenderingContext2D} context Context.
 * @param {ol.Transform} transform Transform.
 * @param {number} viewRotation View rotation.
 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
 *     to skip.
 */
ol.render.canvas.Replay.prototype.replay = function(
    context, transform, viewRotation, skippedFeaturesHash) {
    
    
  this.viewRotation_ = viewRotation;
  this.replay_(context, transform,
      skippedFeaturesHash, this.instructions, undefined, undefined);
};

/**
 * @private
 * @param {CanvasRenderingContext2D} context Context.
 * @param {ol.Transform} transform Transform.
 * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
 *     to skip.
 * @param {Array.<*>} instructions Instructions array.
 * @param {function((ol.Feature|ol.render.Feature)): T|undefined}
 *     featureCallback Feature callback.
 * @param {ol.Extent=} opt_hitExtent Only check features that intersect this
 *     extent.
 * @return {T|undefined} Callback result.
 * @template T
 */
ol.render.canvas.Replay.prototype.replay_ = function(
    context, transform, skippedFeaturesHash,
    instructions, featureCallback, opt_hitExtent) {
    
    


  // When the batch size gets too big, performance decreases. 200 is a good
  // balance between batch size and number of fill/stroke instructions.
  var batchSize =
      this.instructions != instructions || this.overlaps ? 0 : 200;
  while (i < ii) {
    
    
    var instruction = instructions[i];
    var type = /** @type {ol.render.canvas.Instruction} */ (instruction[0]);
    var /** @type {ol.Feature|ol.render.Feature} */ feature, x, y;
    switch (type) {
    
    
      case ol.render.canvas.Instruction.BEGIN_GEOMETRY:
        break;
      case ol.render.canvas.Instruction.BEGIN_PATH:
        break;
      case ol.render.canvas.Instruction.CIRCLE:
        break;
      case ol.render.canvas.Instruction.CLOSE_PATH:
        break;
      case ol.render.canvas.Instruction.CUSTOM:
        break;
      case ol.render.canvas.Instruction.DRAW_IMAGE:
        break;
      case ol.render.canvas.Instruction.DRAW_CHARS:
        break;
      case ol.render.canvas.Instruction.END_GEOMETRY:
        break;
      case ol.render.canvas.Instruction.FILL:
        break;
      case ol.render.canvas.Instruction.MOVE_TO_LINE_TO:
        break;
      case ol.render.canvas.Instruction.SET_FILL_STYLE
        break;
      case ol.render.canvas.Instruction.SET_STROKE_STYLE:   
        break;
      case ol.render.canvas.Instruction.STROKE:
        break;
      default:
        break;
    }
  }
  if (pendingFill) {
    
    
    this.fill_(context);
  }
  if (pendingStroke) {
    
    
    context.stroke();
  }
  return undefined;
};

猜你喜欢

转载自blog.csdn.net/u013240519/article/details/111597890
今日推荐