(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点)

江英杰

华为技术有限公司

canvas 是 ArkUI 开发框架里的画布组件,常用于自定义绘制图形。因为其轻量、灵活、高效等优点,被广泛应用于 UI 界面开发中。本期,我们将为大家介绍 ArkUI 开发框架中 canvas 组件的使用。

一、canvas 介绍

1.1 什么是 canvas?

在 Web 浏览器中,canvas 是一个可自定义 width、height 的矩形画布,画布左上角为坐标原点,以像素为单位,水平向右为 x 轴,垂直向下为 y 轴,画布内所有元素都基于原点进行定位。如图 1 所示,我们通过 <canvas> 标签,创建了一个 width= 1500px,height=900px 的空白画布,我们还需要“画笔”才能绘制图形。canvas 采用轻量的逐像素渲染机制,以 JS 为“画笔”直接控制画布像素,从而实现图形绘制。

图 1 canvas 画布

1.2Canvas 的“画笔”

canvas 本身虽不具备绘制能力,但是提供了获取“画笔”的方法。开发者可通过 getContext('2d') 方法获取 CanvasRenderingContext2D 对象完成 2D 图像绘制,或通过 getContext('webgl') 方法获取 WebGLRenderingContext 对象完成 3D 图像绘制。

目前,ArkUI 开发框架中的 WebGL1.0 及 WebGL2.0 标准 3D 图形绘制能力正在完善中,所以本文将着重介绍 2D 图像的绘制。如图 2 所示,是 CanvasRenderingContext2D 对象提供的部分 2D 图像绘制方法,丰富的绘制方法让开发者能高效地绘制出矩形、文本、图片等。

图 2 图像绘制方法

除此之外,开发者还可以通过获取 OffscreenCanvasRenderingContext2D 对象进行离屏绘制,绘制方法同上。当绘制的图形比较复杂时,频繁地删除与重绘会消耗很多性能。这时,开发者可以根据自身的需求灵活选取离屏渲染的方式,首先通过创建 OffscreenCanvas 对象作为一个缓冲区,然后将内容绘制在 OffscreenCanvas 上,最后再将 OffscreenCanvas 绘制到主画布上,以提高画布性能,确保绘图的质量。

二、canvas 基础绘制方法

通过上节对 canvas 组件的基本介绍,相信大家对 canvas 组件已经有了一定的认识,下面我们将为大家实际演示 canvas 组件在 ArkUI 开发框架中的使用方法。ArkUI 开发框架参考了 Web 浏览器中 canvas 的设计,并在“类 Web 开发范式”及“声明式开发范式”两种开发范式中进行提供,接下来我们将分别介绍这两种开发范式中 canvas 的绘制方法。

2.1 类 Web 开发范式中 canvas 的绘制方法

类 Web 开发范式,使用 HML 标签文件进行布局搭建、CSS 文件进行样式描述,并通过 JS 语言进行逻辑处理。目前,JS 语言的 canvas 绘图功能已经基本上完善,下面我们将通过两个示例,展示基于 JS 语言的 canvas 组件基础使用方法。

2.1.1 矩形填充

CanvasRenderingContext2D 对象提供了 fillRect(x, y, width, height)方法,用于绘制一个填充的矩形。如图 3 所示,在画布内绘制了一个黑色的填充矩形,x 与 y 指定了在 canvas 画布上所绘制的矩形的左上角(相对于原点)的坐标,width 和 height 则设置了矩形的尺寸。

图 3 填充的矩形

示例代码如下:

//创建一个width=1500px,height=900px的画布
<!-- xxx.hml -->
<div>
<canvas ref="canvas" style="width: 1500px; height: 900px; "></canvas>
</div>
//xxx.js
export default {
onShow() {
const el =this.$refs.canvas;
//获取2D绘制对象
const ctx = el.getContext('2d');
//设置填充为黑色
ctx.fillStyle = '#000000';
//设置填充矩形的坐标及尺寸
ctx.fillRect(200, 200, 300, 300);
}
}

2.1.2 缩放与阴影

CanvasRenderingContext2D 对象提供了 scale(x,y) 方法,参数 x 表示横轴方向上缩放倍数,y 表示纵轴方向上缩放的倍数,值得注意的是缩放过程中定位也会被缩放。如图 4 所示,是将上个示例中的填充矩形通过 scale(2,1.5) 缩放,并通过 shadowBlur 方法加上阴影后的效果。

图 4 缩放与添加阴影后的效果

示例代码如下:

//xxx.js
export default {
onShow() {
const el =this.$refs.canvas;
const ctx = el.getContext('2d');
//设置绘制阴影的模糊级别
ctx.shadowBlur = 80;
ctx.shadowColor = 'rgb(0,0,0)';
ctx.fillStyle = 'rgb(0,0,0)';
// x Scale to 200%,y Scale to 150%
ctx.scale(2, 1.5);
ctx.fillRect(200, 200, 300, 300);
}
}

2.2 声明式开发范式中 canvas 的绘制方法

声明式开发范式,采用 TS 语言并进行声明式 UI 语法扩展,从组件、动效和状态管理三个维度提供了 UI 绘制能力,目前已经提供了 canvas 组件绘制能力,但功能仍在完善中。下面我们将通过两个示例展示声明式开发范式中 canvas 组件的基础使用方法。

2.2.1 图片叠加

如图 5 所示,是三张图片叠加的效果,顶层的图片覆盖了底层的图片。通过依次使用 drawImage(x,y, width, height) 方法设置图片坐标及尺寸,后面绘制的图片自动覆盖原来的图像,从而达到预期效果。

图 5 图片叠加

扩展的 TS 语言采用更接近自然语义的编程方式,让开发者可以直观地描述 UI 界面,示例代码如下:

@Entry
@Component
struct IndexCanvas1 {
private settings:RenderingContextSettings = new RenderingContextSettings(true);
//获取绘图对象
private ctx: RenderingContext = new RenderingContext(this.settings);
//列出所要用到的图片
private img:ImageBitmap = new ImageBitmap("common/bg.jpg");
build() {
Column() {
//创建canvas
Canvas(this.ctx)
.width(1500)
.height(900)
.border({color:"blue",width:1,})
.backgroundColor('#ffff00')
//开始绘制
.onReady(() => {
this.ctx.drawImage( this.img,400,200,540,300);
this.ctx.drawImage( this.img,500,300,540,300);
this.ctx.drawImage( this.img,600,400,540,300);
})
}
.width('100%')
.height('100%')
}
}

2.2.2 点击创建线性渐变

如图 6 所示,是一个线性渐变效果。基于 canvas 扩展了一个 Button 组件,通过点击 “Click” 按钮,触发 onClick() 方法,并通过调用 createLinearGradient() 方法,绘制出了一个线性渐变色。

图 6 图片上添加文字

示例代码如下:

@Entry
@Component
struct GradientExample {
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: RenderingContext = new RenderingContext(this.settings);
private gra: CanvasGradient = new CanvasGradient();
build() {
Column({ space: 5 }) {
//创建一个画布
Canvas(this.context)
.width(1500)
.height(900)
.backgroundColor('#ffff00 ')
Column() {
//设置按钮的样式
Button('Click').width(250).height(100).backgroundColor('#000000')
.onClick(() => {
//创建一个线性渐变色
var grad = this.context.createLinearGradient(600, 200, 400, 750)
grad.addColorStop(0.0, 'red');
grad.addColorStop(0.5, 'white');
grad.addColorStop(1.0, 'green');
this.context.fillStyle = grad;
this.context.fillRect(400, 200, 550, 550);
})
}.alignItems(HorizontalAlign.center)
}
}
}

三、飞机大战小游戏绘制实践

如图 7 所示,是一款”飞机大战”小游戏,通过控制战机的移动摧毁敌机。如何使用 ArkUI 开发框架提供的 canvas 组件轻松实现这个经典怀旧的小游戏?实现思路及关键代码如下:

图 7 飞机大战小游戏

1. 首先列出游戏所用到的图片

private imgList:Array<string> = ["xx.png","xx.png"…];

2. 将图片渲染到 canvas 画布上

let img:ImageBitmap = new ImageBitmap("图片路径(如common/images)/"+this.imgList[数组下标]);
this.ctx.drawImage( img,150/* x坐标*/, 150/* y坐标*/, 600/*宽*/, 600/*高*/)

3. 绘制背景图片和战机向下移动的效果

this.ctx.drawImage(this.bg, 0, this.bgY);
this.ctx.drawImage(this.bg, 0, this.bgY - 480);
this.bgY++ == 480 && (this.bgY = 0);

4. 使用 Math.round 函数随机获取敌机图片并渲染到画布上,并且改变敌机 y 轴坐标,使它向下运动。

Efight = Math.round(Math.random()*7);
//前七张为敌机图片。
let img:ImageBitmap = new ImageBitmap("common/img"+this.imgList[Efight]);
this.ctx.drawImage(img, 0, this.Eheight + 50);//渲染敌机

5. 在页面每隔 120s 出现一排子弹,之后减小或增大(x,y)轴的坐标达到子弹射出效果。

let i= 0;
setInterval(()=>{
this.ctx.drawImage(this.bulImg1,image.x – 10 – (i *10) , image.x + (i *10))
this.ctx.drawImage(this.bulimg2, this. bulImg1,image.x – (i *10) , i image.x + (i *10))
this.ctx.drawImage(this.bulimg3, image.x + 10 + (i *10), image.x + (i *10))
i ++;
},120)

6. 使用 onTouch 方法获取战机移动位置,获取拖动的坐标后重新设置战机的图片坐标,使战机实现拖动效果。

.onTouch((event)=>{
var offsetX = event.localX ||event.touches[0].localX;
var offsetY = event.localY ||event.touches[0].localY;
var w = this.heroImg[0].width,
h = this.heroImg[0].height;
var nx = offsetX - w / 2,
ny = offsetY - h / 2;
nx < 20 - w / 2 ? nx = 20 - w / 2 : nx > (this.windowWidth - w / 2 - 20) ? nx =
(this.windowWidth - w / 2 - 20) : 0;
ny < 0 ? ny = 0 : ny > (this.windowHeight - h / 2) ? ny = (this.windowHeight –
h/2) : 0;
this.hero.x = nx;
this.hero.y = ny;
this.hero.count = 2;

注:本示例引用了部分开源资源,感兴趣的开发者可参考此开源资源,结合文中的实现思路补全代码。(https://github.com/xs528/game

以上就是本期全部内容,期待广大开发者能通过 canvas 组件绘制出精美的图形,更多 canvas 组件的详细使用方法,请参考文档进行学习:

https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-components-canvas-canvas-0000000000621808

OpenHarmony 3.1 Beta 版本关键特性解析——ArkUI canvas组件的更多相关文章

  1. OpenHarmony 3.1 Beta版本关键特性解析——ArkUI容器类API介绍

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 刘鑫 容器类,顾名思义就是存储的类,用于存储各种数据类型的元素,并具备一系列处理数据元素的方法.在 ArkUI 开发框 ...

  2. OpenHarmony 3.1 Beta版本关键特性解析——HiStreamer框架大揭秘

    ​(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点)​ 陈国栋 数字多媒体技术在过去的数十年里得到了飞速的发展,多媒体终端设备如智能音箱.智能门锁.智能手表广泛应用于人们 ...

  3. OpenHarmony 3.1 Beta版本关键特性解析——HAP包安装实现剖析

    ​(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点)​ 石磊 随着社会的不断发展,人们逐渐注重更加高效.舒适.便捷.有趣的生活和工作体验. OpenAtom OpenHa ...

  4. OpenHarmony 3.1 Beta版本关键特性解析——探秘隐式查询

    ​(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点)​ 徐浩 隐式查询是 OpenAtom OpenHarmony(以下简称"OpenHarmony" ...

  5. OpenHarmony 3.1 Beta版本关键特性解析——OpenHarmony图形框架

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 李煜 华为技术有限公司 崔坤华为技术有限公司 众所周知,动画是系统和应用与用户交互的重要环节.动画效果的好坏会直接影响 ...

  6. OpenHarmony 3.1 Beta版本关键特性解析——分布式DeviceProfile

    (以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 成翔 OpenAtom OpenHarmony(以下简称"OpenHarmony")作为分布式操作 ...

  7. OpenHarmony3.1 Release版本关键特性解析——Enhanced SWAP内存管理

    樊成阳 华为技术有限公司内核专家 陈杰 华为技术有限公司内核专家 OpenAtom OpenHarmony(以下简称"OpenHarmony")是面向全场景泛终端设备的操作系统,终 ...

  8. Unity 5.6 beta版本新特性

    http://manew.com/thread-98549-1-1.html 最新发布的beta版改进了编辑器和2D功能,图形性能更佳,加入新的视频播放器,并添加了对Facebook Gameroom ...

  9. OpenHarmony 3.1 Release版本发布

    OpenHarmony 3.1 Release 版本概述 当前版本在OpenHarmony 3.1 Beta的基础上,更新支持以下能力: 标准系统基础能力增强 本地基础音视频播放能力.视频硬编解码.相 ...

随机推荐

  1. 报错———http://mybatis.org/dtd/mybatis-3-mapper.dtd 报红解决方案

    初次使用mybatis时,下面红线上的地址报红. 解决方法是:将http://mybatis.org/dtd/mybatis-3-mapper.dtd拷贝.添加到下面标记处.

  2. Linux kernel cfg80211_mgd_wext_giwessid缓冲区溢出漏洞

    受影响系统:Linux kernel <= 5.3.2描述:CVE(CAN) ID: CVE-2019-17133 Linux kernel是开源操作系统Linux所使用的内核. Linux k ...

  3. 14FPGA综设之图像边沿检测的sobel算法

    连续学习FPGA基础课程接近一个月了,迎来第一个有难度的综合设计,图像的边沿检测算法sobel,用verilog代码实现算法功能. 一设计功能 (一设计要求) (二系统框图) 根据上面的系统,Veri ...

  4. 使用过 Redis 做异步队列么,你是怎么用的?

    答:一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息.当 lpop 没有 消息的时候,要适当 sleep 一会再重试. 如果对方追问可不可以不用 sleep 呢? list ...

  5. 深入理解Java虚拟机-HotSpot虚拟机对象探秘

    一.对象的创建过程 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那就先执行相应的类 ...

  6. kafka的message格式是什么样的?

    一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成 header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成 ...

  7. spring @Bean和@Order 官方doc理解

    今天阅读了spring的官方代码,(大概)理解了@Bean和@Order如何使用. @Bean 官方代码解读: 0.@Bean的注入,用于表示这个bean被spring容器管理(创建.销毁)(官方英文 ...

  8. iOS全埋点解决方案-界面预览事件

    前言 ​ 我们先了解 UIViewController 生命周期相关的内容和 iOS 的"黑魔法" Method Swizzling.然后再了解页面浏览事件($AppViewScr ...

  9. 使用jquery-webcam插件,实现人脸采集并转base64

    项目需求:在ie或chrome浏览器下,调用电脑摄像头(确保使用的是笔记本电脑,或者摄像头功能正常使用的台式机),进行人脸图像采集预览,并将图片的base64码传入到后台进行后续操作.该demo适用于 ...

  10. 手把手教你从零写一个简单的 VUE--模板篇

    教程目录1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 Hello,我又回来了,上一次的文章教会了大家如何书写一个简单 VUE,里面实现了VUE 的数据驱动视图 ...