1# OffscreenCanvas 2 3OffscreenCanvas组件用于自定义绘制图形。 4 5使用[Canvas](ts-components-canvas-canvas.md)组件或[Canvas API](ts-canvasrenderingcontext2d.md)时,渲染、动画和用户交互通常发生在应用程序的主线程上,与画布动画和渲染相关的计算可能会影响应用程序性能。OffscreenCanvas提供了一个可以在屏幕外渲染的画布,这样可以在单独的线程中运行一些任务,从而避免影响应用程序主线程性能。 6 7> **说明:** 8> 9> 该组件从API Version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 10 11## 子组件 12 13不支持。 14 15## 接口 16 17OffscreenCanvas(width: number, height: number, unit?: LengthMetricsUnit) 18 19**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。 20 21**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 22 23**系统能力:** SystemCapability.ArkUI.ArkUI.Full 24 25**参数:** 26 27| 参数名 | 类型 | 必填 | 说明 | 28| ------ | -------- | ---- | ------------------------------------- | 29| width | number | 是 | OffscreenCanvas组件的宽度。<br>默认单位为vp。 | 30| height | number | 是 | OffscreenCanvas组件的高度。<br>默认单位为vp。 | 31| unit<sup>12+</sup> | [LengthMetricsUnit](../js-apis-arkui-graphics.md#lengthmetricsunit12) | 否 | 用来配置OffscreenCanvas对象的单位模式,配置后无法动态更改,配置方法同[CanvasRenderingContext2D](ts-canvasrenderingcontext2d.md#lengthmetricsunit12)。<br>默认值:DEFAULT。 | 32 33## 属性 34 35**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。 36 37**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 38 39**系统能力:** SystemCapability.ArkUI.ArkUI.Full 40 41OffscreenCanvas支持以下属性: 42 43| 名称 | 类型 | 只读 | 可选 | 说明 | 44| ------ | ------ | ------ | ------- | ---- | 45| width | number | 否 | 否 | OffscreenCanvas组件的宽度。<br>默认单位为vp。 | 46| height | number | 否 | 否 | OffscreenCanvas组件的高度。<br>默认单位为vp。 | 47 48### width 49 50```ts 51// xxx.ets 52@Entry 53@Component 54struct OffscreenCanvasPage { 55 private settings: RenderingContextSettings = new RenderingContextSettings(true); 56 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 57 private offCanvas: OffscreenCanvas = new OffscreenCanvas(200, 300) 58 59 build() { 60 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) { 61 Column() { 62 Canvas(this.context) 63 .width('100%') 64 .height('100%') 65 .borderWidth(5) 66 .borderColor('#057D02') 67 .backgroundColor('#FFFFFF') 68 .onReady(() => { 69 let offContext = this.offCanvas.getContext("2d", this.settings) 70 offContext.fillStyle = '#CDCDCD' 71 offContext.fillRect(0, 0, this.offCanvas.width, 150) 72 let image = this.offCanvas.transferToImageBitmap() 73 this.context.setTransform(1, 0, 0, 1, 50, 200) 74 this.context.transferFromImageBitmap(image) 75 }) 76 } 77 }.width('100%').height('100%') 78 } 79} 80``` 81 82 83 84### height 85 86```ts 87// xxx.ets 88@Entry 89@Component 90struct OffscreenCanvasPage { 91 private settings: RenderingContextSettings = new RenderingContextSettings(true); 92 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 93 private offCanvas: OffscreenCanvas = new OffscreenCanvas(200, 300) 94 95 build() { 96 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) { 97 Column() { 98 Canvas(this.context) 99 .width('100%') 100 .height('100%') 101 .borderWidth(5) 102 .borderColor('#057D02') 103 .backgroundColor('#FFFFFF') 104 .onReady(() => { 105 let offContext = this.offCanvas.getContext("2d", this.settings) 106 offContext.fillStyle = '#CDCDCD' 107 offContext.fillRect(0, 0, 100, this.offCanvas.height) 108 let image = this.offCanvas.transferToImageBitmap() 109 this.context.setTransform(1, 0, 0, 1, 50, 200) 110 this.context.transferFromImageBitmap(image) 111 }) 112 } 113 }.width('100%').height('100%') 114 } 115} 116``` 117 118 119 120## 方法 121 122### transferToImageBitmap 123 124transferToImageBitmap(): ImageBitmap 125 126从OffscreenCanvas组件中最近渲染的图像创建一个ImageBitmap对象。 127 128**卡片能力:** 从API version 9开始,该接口支持在ArkTS卡片中使用。 129 130**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 131 132**系统能力:** SystemCapability.ArkUI.ArkUI.Full 133 134**返回值:** 135 136| 类型 | 描述 | 137| -------------------------------------------------- | ----------------------- | 138| [ImageBitmap](ts-components-canvas-imagebitmap.md) | 创建的ImageBitmap对象。 | 139 140**示例:** 141 142```ts 143// xxx.ets 144@Entry 145@Component 146struct OffscreenCanvasPage { 147 private settings: RenderingContextSettings = new RenderingContextSettings(true) 148 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings) 149 private offCanvas: OffscreenCanvas = new OffscreenCanvas(300, 500) 150 151 build() { 152 Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { 153 Canvas(this.context) 154 .width('100%') 155 .height('100%') 156 .borderWidth(5) 157 .borderColor('#057D02') 158 .backgroundColor('#FFFFFF') 159 .onReady(() => { 160 let offContext = this.offCanvas.getContext("2d", this.settings) 161 offContext.fillStyle = '#CDCDCD' 162 offContext.fillRect(0, 0, 300, 500) 163 offContext.fillStyle = '#000000' 164 offContext.font = '70px serif bold' 165 offContext.fillText("Offscreen : Hello World!", 20, 60) 166 let image = this.offCanvas.transferToImageBitmap() 167 this.context.transferFromImageBitmap(image) 168 }) 169 } 170 .width('100%') 171 .height('100%') 172 } 173} 174``` 175 176 177 178### getContext<sup>10+</sup> 179 180getContext(contextType: "2d", options?: RenderingContextSettings): OffscreenCanvasRenderingContext2D 181 182返回OffscreenCanvas组件的绘图上下文。 183 184**原子化服务API:** 从API version 11开始,该接口支持在原子化服务中使用。 185 186**系统能力:** SystemCapability.ArkUI.ArkUI.Full 187 188**参数:** 189 190| 参数名 | 类型 | 必填 | 说明 | 191| ----------- | ------------------------------------------------------------ | ---- | ------------------------------------------------------------ | 192| contextType | string | 是 | OffscreenCanvas组件绘图上下文的类型,当前仅支持"2d"类型。| 193| options | [RenderingContextSettings](ts-canvasrenderingcontext2d.md#renderingcontextsettings) | 否 | 用来配置OffscreenCanvasRenderingContext2D对象的参数,见[RenderingContextSettings](ts-canvasrenderingcontext2d.md#renderingcontextsettings)。<br>默认值:null。 | 194 195**返回值:** 196 197| 类型 | 描述 | 198| ------------------------------------------------------------ | --------------------------------- | 199| [OffscreenCanvasRenderingContext2D](ts-offscreencanvasrenderingcontext2d.md) | OffscreenCanvas组件的绘图上下文。如果getContext方法的入参contextType为"2d"以外类型(包括null或者undefined),返回null。 | 200 201**示例:** 202 203```ts 204@Entry 205@Component 206struct OffscreenCanvasExamplePage { 207 private settings: RenderingContextSettings = new RenderingContextSettings(true); 208 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 209 private offscreenCanvas: OffscreenCanvas = new OffscreenCanvas(600, 800) 210 211 build() { 212 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) { 213 Column() { 214 Canvas(this.context) 215 .width('100%') 216 .height('100%') 217 .backgroundColor('#FFFFFF') 218 .onReady(() => { 219 let offContext = this.offscreenCanvas.getContext("2d", this.settings) 220 offContext.font = '70px sans-serif' 221 offContext.fillText("Offscreen : Hello World!", 20, 60) 222 offContext.fillStyle = "#0000ff" 223 offContext.fillRect(230, 350, 50, 50) 224 offContext.fillStyle = "#EE0077" 225 offContext.translate(70, 70) 226 offContext.fillRect(230, 350, 50, 50) 227 offContext.fillStyle = "#77EE0077" 228 offContext.translate(-70, -70) 229 offContext.fillStyle = "#00ffff" 230 offContext.rotate(45 * Math.PI / 180); 231 offContext.fillRect(180, 120, 50, 50); 232 offContext.rotate(-45 * Math.PI / 180); 233 offContext.beginPath() 234 offContext.moveTo(10, 150) 235 offContext.bezierCurveTo(20, 100, 200, 100, 200, 20) 236 offContext.stroke() 237 offContext.fillStyle = '#FF00FF' 238 offContext.fillRect(100, 100, 60, 60) 239 let imageData = this.offscreenCanvas.transferToImageBitmap() 240 this.context.transferFromImageBitmap(imageData) 241 }) 242 }.width('100%').height('100%') 243 } 244 .width('100%') 245 .height('100%') 246 } 247} 248``` 249 250 251 252 253## OffscreenCanvas支持并发线程绘制 254 255从API version 11开始,当应用创建[Worker线程](../../../arkts-utils/worker-introduction.md),支持使用postMessage将OffscreenCanvas实例传到Worker中进行绘制,并使用onmessage接收Worker线程发送的绘制结果进行显示。 256 257> **说明:** 258> 259> OffscreenCanvas对象使用getContext获取绘图上下文后,不允许通过postMessage传该对象给其他线程,否则抛出异常。 260> 261> 已经通过postMessage传OffscreenCanvas对象到某一线程,声明该对象的线程不允许该对象使用getContext和transferToImageBitmap方法,否则抛出异常。 262> 263> 已经通过postMessage传OffscreenCanvas对象到某一线程,不允许再将该对象通过postMessage传给其他线程,否则抛出异常。 264 265**示例:** 266 267```ts 268import { worker } from '@kit.ArkTS'; 269 270@Entry 271@Component 272struct OffscreenCanvasExamplePage { 273 private settings: RenderingContextSettings = new RenderingContextSettings(true); 274 private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings); 275 private myWorker = new worker.ThreadWorker('entry/ets/workers/Worker.ts'); 276 277 build() { 278 Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Start, justifyContent: FlexAlign.Start }) { 279 Column() { 280 Canvas(this.context) 281 .width('100%') 282 .height('100%') 283 .borderWidth(5) 284 .borderColor('#057D02') 285 .backgroundColor('#FFFFFF') 286 .onReady(() => { 287 let offCanvas = new OffscreenCanvas(600, 800) 288 this.myWorker.postMessage({ myOffCanvas: offCanvas }); 289 this.myWorker.onmessage = (e): void => { 290 if (e.data.myImage) { 291 let image: ImageBitmap = e.data.myImage 292 this.context.transferFromImageBitmap(image) 293 } 294 } 295 296 }) 297 }.width('100%').height('100%') 298 } 299 .width('100%') 300 .height('100%') 301 } 302} 303``` 304 305Worker线程在onmessage中接收到主线程postMessage发送的OffscreenCanvas,并进行绘制。 306 307```ts 308workerPort.onmessage = (e: MessageEvents) => { 309 if (e.data.myOffCanvas) { 310 let offCanvas: OffscreenCanvas = e.data.myOffCanvas 311 let offContext = offCanvas.getContext("2d") 312 offContext.fillStyle = '#CDCDCD' 313 offContext.fillRect(0, 0, 200, 150) 314 let image = offCanvas.transferToImageBitmap() 315 workerPort.postMessage({ myImage: image }); 316 } 317} 318``` 319 320 321 322