EsriJS:CustomLayerView调用requestRender报错,display未设置
解决BaseLayerView2D的display/container未设置错误
核心问题原因
BaseLayerView2D的container和display是由MapView/SceneView在初始化LayerView时自动传入并初始化的,不能手动调用super.initialize()而不传递视图提供的参数;同时requestRender()必须在LayerView初始化完成(即display已存在)后调用。
正确实现步骤
1. 完善CustomLayer的createLayerView方法
自定义Layer必须实现createLayerView,作为视图创建LayerView的入口,视图会自动处理LayerView的初始化流程:
import { Layer } from "esri/layers/Layer"; import { CustomLayerView2D } from "./CustomLayerView2D"; export class CustomLayer extends Layer { geometry: __esri.Geometry | null = null; tileInfo: __esri.TileInfo; constructor(props?: Partial<CustomLayer>) { super(props); // 初始化tileInfo等必要属性 this.tileInfo = props?.tileInfo ?? { /* 你的tileInfo配置 */ }; } // 视图会自动调用该方法创建LayerView,并传入初始化参数 createLayerView(view: __esri.MapView): Promise<CustomLayerView2D> { return Promise.resolve(new CustomLayerView2D(this)); } }
2. 正确实现CustomLayerView2D的initialize方法
必须接收视图传入的options参数,并调用父类的initialize来完成container和display的初始化:
import { BaseLayerView2D } from "esri/views/layers/BaseLayerView2D"; import { projection } from "esri/geometry"; import { CustomLayer } from "./CustomLayer"; export class CustomLayerView2D extends BaseLayerView2D { projectedGeometry: __esri.Geometry | null = null; needsImageUpdate: boolean = false; // 可选:如果需要渲染用的canvas,提前声明 private canvas?: HTMLCanvasElement; constructor(layer: CustomLayer) { super(layer); // 监听layer的geometry变化,在初始化完成后处理 this.watch("layer.geometry", this.handleGeometryChange.bind(this)); } // 视图会自动调用该方法,传入包含container、view的options initialize(options: { container: HTMLElement; view: __esri.MapView }): void { // 先调用父类initialize,自动设置this.container和this.display super.initialize(options); // 在这里初始化自定义渲染元素,比如添加canvas到container this.canvas = document.createElement("canvas"); this.container.appendChild(this.canvas); // 可以设置canvas样式,比如占满container this.canvas.style.width = "100%"; this.canvas.style.height = "100%"; } private handleGeometryChange(geometry: __esri.Geometry, oldGeometry: __esri.Geometry): void { const layer = this.layer as CustomLayer; if (!layer.geometry) { this.projectedGeometry = null; this.needsImageUpdate = true; // 确保display已初始化后再调用requestRender this.display && this.requestRender(); return; } if (geometry !== oldGeometry) { projection.load().then(() => { this.projectedGeometry = projection.project( layer.geometry, layer.tileInfo.spatialReference, projection.getTransformation(layer.geometry.spatialReference, layer.tileInfo.spatialReference) ); this.needsImageUpdate = true; this.display && this.requestRender(); }); } else { this.needsImageUpdate = true; this.display && this.requestRender(); } } // 必须实现render方法,requestRender会触发该方法执行渲染逻辑 render(): void { if (!this.needsImageUpdate || !this.projectedGeometry || !this.canvas) return; // 在这里编写你的自定义渲染逻辑,比如绘制projectedGeometry const ctx = this.canvas.getContext("2d"); if (!ctx) return; // 示例:清空canvas并绘制简单图形(需根据实际geometry类型调整) ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); // 这里替换为你的实际渲染代码,比如将projectedGeometry转换为屏幕坐标后绘制 // ... this.needsImageUpdate = false; } }
3. 关键注意事项
- 不要手动调用
super.initialize()而不传递视图提供的options参数,否则会导致container和display未初始化。 - 调用
requestRender()前必须确保this.display存在(即LayerView已完成初始化),可以通过判断this.display是否为真来避免报错。 - 必须实现
render方法,否则requestRender()不会执行任何渲染操作。
内容的提问来源于stack exchange,提问作者SupremeKurt
相关产品推荐
相关产品推荐

