鸿蒙OS开发使用Canvas组件绘制天气曲线图

news2024/10/1 10:24:57

参考下文: 鸿蒙征文 | 使用Canvas组件绘制天气曲线图_harmonyos_鸑鷟407-HarmonyOS开发者社区效果图: 原理 使用贝塞尔曲线 首先可以了解一下贝塞尔曲线。 如果看不懂也没关系,这里会直接讲绘制曲线的步骤。 使用CanvasRenderingContext2D对象。 首先使用beginPath方法确定起始点。 这里会循环地用到bezierCurveTo(三次贝塞尔曲线)方法。该方法需要三个点的坐标,即图上的点1、2、3。 这里的点3就表示温度的点。为了让曲线更平滑,我们让点1的高度与起始 鸑鷟407 HarmonyOS开发者社区icon-default.png?t=N7T8https://harmonyosdev.csdn.net/660cdf2c9ab37021bfa7a47c.html

效果图:(左右可以滑动)


@Entry
@Component
struct csPage {
  tempMax : number[] = [21, 38, 17, 21, 21, 32, 24, 22, 25, 33, 24, 26, 25, 34, 28];
  tempMin : number[] = [14, 21, 12, 13, 18, 23, 17, 15, 13, 18, 18, 10, 15, 24, 20];
  weatherDates: string[] = ['05/04', '05/05', '05/06', '05/07', '05/08', '05/09', '05/10', '05/11', '05/12', '05/13', '05/14', '05/15', '05/16', '05/17', '05/18'];
  weatherConditions: string[] = ['小雨', '多云', '多云', '晴', '晴', '小雨', '大雨', '晴', '多云', '多云', '小雨', '晴', '晴', '多云', '小雨'];
  icon: string[] =              ['100', '101', '102', '103', '104', '300', '301', '302', '303', '304', '305', '306', '307', '308', '309'];
  windDirDay: string[] =              ['西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风', '西南风'];
  windScaleDay: string[] =              ['1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2', '1-2'];

  // 定义左右边距
  sideMargin: number = 40; // 根据需要调整
  //使用RenderingContext在Canvas组件上进行绘制,绘制对象可以是矩形、文本、图片等。
  settings: RenderingContextSettings = new RenderingContextSettings(true);
  context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
  // canvasHeight:表示曲线图高度,itemWidth:表示每两天的温度点之间的距离。
  canvasHeight: number = 250;
  itemWidth: number = 50;



  build() {
    Row() {
      Column({ space: 15 }) {
        Text('7天趋势预报')
          .fontSize(18)
          .padding(10)
          .margin({top:15})
          .fontWeight(FontWeight.Bold)
        Scroll() {
          Canvas(this.context)
            .width(this.tempMax.length * this.itemWidth + this.itemWidth + this.sideMargin * 2)
            .height('100%')
            .onReady(() => {
              //找出高温曲线的最大值,和低温曲线的最小值,用于后续确定曲线竖直方向的比例
              const maxTemperature: number = Math.max(...this.tempMax);
              const minTemperature: number = Math.min(...this.tempMin);
              //最高-最低温度的上下距离 step 表示每改变 1℃,纵坐标改变的高度
              const step: number = this.canvasHeight * 0.4 / (maxTemperature - minTemperature);
              const curveChartMargin: number = this.canvasHeight * 0.09;

              //设置曲线样式
              this.context.lineWidth = 1;
              this.context.font = '13vp sans-serif';
              this.context.fillStyle = '#000000';
              this.context.strokeStyle = 'blue'
              this.context.globalAlpha = 1;
              this.context.textAlign='start'

              //由于同一天的高温点、低温点的x坐标相同,所以x坐标使用同一组数据。
              let xPos: number[] = [];
              let tempMaxPos: number[] = [];
              let tempMin: number[] = [];
              //确定温度点的坐标,再绘制,并绘制温度文字
              for (let i: number = 0; i < this.tempMax.length; i++) {
                // 确定每个点的坐标,包括高温和低温,其中,高温和低温坐标的横坐标都是一致的
                let x: number = this.sideMargin + (i * this.itemWidth);
                let yHeight: number = this.canvasHeight - (curveChartMargin + (this.tempMax [i] - minTemperature) * step);
                let yLow: number = this.canvasHeight - (curveChartMargin + (this.tempMin[i] - minTemperature) * step);

                // 存放数据
                xPos.push(x);
                tempMaxPos.push(yHeight);
                tempMin.push(yLow);

                // 给每个点画出一个圆并填充颜色,这里设置圆的半径为2
                this.context.fillStyle = "blue"; // 设置低温点颜色为蓝色
                let region: Path2D = new Path2D();
                region.ellipse(x, yHeight, 2, 2, 0, 0, Math.PI * 2);
                region.ellipse(x, yLow, 2, 2, 0, 0, Math.PI * 2);
                this.context.fill(region);



                // 绘制日期
                this.context.fillStyle = "black"; // 可以设置文字颜色
                let dateStr: string = this.weatherDates[i];
                this.context.fillText(dateStr, x - this.context.measureText(dateStr).width / 2,  20);
                let highWindDirDayStr:string=this.windDirDay[i]
                this.context.fillText(highWindDirDayStr,x-this.context.measureText(highWindDirDayStr).width/2,35)
                // 绘制天气图标
                let icon: string = Q_Weather_Image(this.icon[i]);
                let   imgIcon = new ImageBitmap(icon)
                this.context.drawImage(imgIcon,x - this.context.measureText(dateStr).width / 2,45, 30, 30);
                // 绘制天气状态
                let  highConditionStr: string = this.weatherConditions[i];
                this.context.fillText(highConditionStr, x - this.context.measureText(highConditionStr).width / 2, 90);




                // 绘制高温低温的文字
                this.context.fillStyle = "black"; // 可以设置文字颜色
                let maxTemperatureStr: string = `${this.tempMax[i]}℃`;
                let minTemperatureStr: string = `${this.tempMin[i]}℃`;
                this.context.fillText(maxTemperatureStr, x - this.context.measureText(maxTemperatureStr).width / 2, yHeight - 6);
                this.context.fillText(minTemperatureStr, x - this.context.measureText(minTemperatureStr).width / 2, yLow + 15);


                // 绘制天气状态
                let conditionStr: string = this.weatherConditions[i];
                this.context.fillText(conditionStr, x - this.context.measureText(conditionStr).width / 2, this.canvasHeight + 60);
                //绘制风向
                let  windDirDayStr:string=this.windDirDay[i]
                this.context.fillText(windDirDayStr,x-this.context.measureText(windDirDayStr).width/2,this.canvasHeight+77)
                //绘制风向等级
                let windScaleDayStr:string= `${this.windScaleDay[i]}级`
                this.context.fillText(windScaleDayStr,x-this.context.measureText(windScaleDayStr).width/2,this.canvasHeight+95)
                // 绘制天气图标
                // 下载并绘制天气图标
                let iconUrl: string = Q_Weather_Image(this.icon[i]);
                let   img = new ImageBitmap(iconUrl)
                this.context.drawImage(img,x - this.context.measureText(windScaleDayStr).width / 2.2, this.canvasHeight+ 15, 30, 30);


              }

              // 绘制高温曲线
              this.context.beginPath();
              this.context.moveTo(xPos[0], tempMaxPos[0]);
              for (let i: number = 1; i < xPos.length; i++) {
                //let x0: number = i * this.itemWidth;
                // let x0: number = sideMargin + i * this.itemWidth;
                // let y0: number = this.canvasHeight - (curveChartMargin + (this.tempMax[i - 1] - minTemperature) * step);
                let x0: number = xPos[i - 1];
                let y0: number = tempMaxPos[i - 1];
                this.context.bezierCurveTo(x0 + (xPos[i] - x0) * 0.3, y0, xPos[i] - (xPos[i] - x0) * 0.3, tempMaxPos[i], xPos[i], tempMaxPos[i]);
              }
              this.context.stroke();

              // 绘制低温曲线
              this.context.beginPath();
              this.context.moveTo(xPos[0], tempMin[0]);
              for (let i: number = 1; i < xPos.length; i++) {
               // let x0: number = i * this.itemWidth;
               //  let x0: number = sideMargin + i * this.itemWidth;
               //  let y0: number = this.canvasHeight - (curveChartMargin + (this.tempMin[i - 1] - minTemperature) * step);
                let x0: number = xPos[i - 1];
                let y0: number = tempMin[i - 1];
                this.context.bezierCurveTo(x0 + (xPos[i] - x0) * 0.3, y0, xPos[i] - (xPos[i] - x0) * 0.3, tempMin[i], xPos[i], tempMin[i]);
              }
              this.context.stroke();
            });
        }
        .scrollable(ScrollDirection.Horizontal)
        .scrollBar(BarState.Off);
      }
      .width('100%')
      .height('60%')
      .backgroundColor($r('app.color.home_bg'))
      .borderRadius(20)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor($r('app.color.daily_bg'))

  }
}

function Q_Weather_Image(img: string): string {
  let url = `https://a.hecdn.net/img/common/icon/202106d/${img}.png`;
  return url;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS code初学笔记

一、调试 1.1添加查看全部数组元素 监视->*(type(*)[number])begin 其中type表示类型int、char等。number表示要查看的数量。begin是起始地址指针&#xff0c;即数组名。

github使用gh-pages部署vue静态网站(简单易懂)

github使用gh-pages部署vue静态网站 当我们想把自己的网站部署到一个静态网站上&#xff0c;Github Pages是一个很好的选择&#xff08;稳定、可靠、不花钱&#xff09; 假设你已经有一个项目并且已经发布到github上了&#xff0c;先把项目git clone到本地 &#xff0c;接着在…

第二季度云计算市场份额榜单:微软下滑,谷歌上升,AWS仍保持领先

2024 年第二季度&#xff0c;随着企业云支出达到 790 亿美元的新高&#xff0c;三大云计算巨头微软、谷歌云和 AWS的全球云市场份额发生了变化。 根据新的市场数据&#xff0c;以下是 2024 年第二季度全球云市场份额结果和六大世界领先者&#xff0c;其中包括 AWS、阿里巴巴、…

条形码与二维码报表

概述 条形码与二维码&#xff1a;演示条形码与二维码&#xff0c;条形码数据将来自于关联的字段值。支持各种常用的条形码与二维码。 应用场景 如下图所示&#xff0c;简单展示数据 示例说明 数据准备 在数据面板中添加数据集&#xff0c;可选择Json数据集和API服务数据…

​全国大学分布SHP数据分享

数据是GIS的血液&#xff01; 我们在《全国地铁路线及站点SHP数据》一文中&#xff0c;为你分享过全国地铁路线及站点数据。 现在再为你分享全国大学信息分布SHP数据&#xff0c;你可以在文末查看该数据的领取方法。 全国大学分布数据 据不完全统计至2024年6月20日&#xf…

护眼落地灯十大品牌排名:2024十大值得入手的护眼落地灯盘点

2024十大值得入手的护眼落地灯是哪款&#xff1f;随着生活水平的提高&#xff0c;许多家长在关心孩子身心健康的同时也关注着孩子的视力健康&#xff0c;很多家长了解到光线对孩子视力的影响&#xff0c;都纷纷给孩子准备护眼大路灯&#xff0c;但是面对市面上众多的护眼大路灯…

Java HotSpot虚拟机中的内存管理手册阅读笔记

显示与自动内存管理 内存管理是计算机编程中的一个重要概念&#xff0c;它涉及到跟踪和控制程序使用内存的方式。内存管理可以分为两种主要类型&#xff1a;显式内存管理和自动内存管理。 显式内存管理 在显式内存管理系统中&#xff0c;程序员必须手动分配和释放内存。这通…

筒射巡飞无人机技术详解

筒射巡飞无人机&#xff08;Launch and Recovery by Tube, LRAT&#xff09;作为一种新型无人机系统&#xff0c;其机体结构设计充分考虑了便携性、隐蔽性及空气动力学效率。该无人机通常采用模块化设计&#xff0c;主体结构紧凑&#xff0c;能够适配于标准发射筒内进行发射与回…

CISP和NISP到底啥区别?网络安全行业考证必知

随着网络攻击的日益频繁和复杂化&#xff0c;信息安全专业人才的需求也随之激增。 在众多信息安全认证中&#xff0c;CISP与NISP尤为受到关注&#xff0c;不少搞安全的朋友应该都对他们有所耳闻。 但在选择认证时&#xff0c;往往又犯了难。 这两个安全认证的差别在哪里&#x…

基于Hadoop的PM2.5分布可视化系统设计

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍引言研究背景国内外研究现状研究目的研究意义 关键技术理论介绍Hadoop相关组件介绍分布式集群介绍 Hadoop集群搭建及数据准备Hadoop全套组件搭建数据集介绍数据预处理 Hadoo的PM2.5…

U盘中毒后文件乱码?数之寻软件助你高效恢复数据

一、U盘中毒与文件乱码的困扰 在数字化时代&#xff0c;U盘作为便携式存储设备&#xff0c;广泛应用于数据传输与备份中。然而&#xff0c;U盘在方便我们生活与工作的同时&#xff0c;也面临着诸多安全风险。其中&#xff0c;U盘“中毒”导致的文件乱码问题尤为常见&#xff0…

NDI导播系统Multiview Pro使用初探

目录 一、软件安装 二、系统启动 三、登录系统 四、开始使用 我一直推崇NDI,这是一项非常好的技术,它实现了全IP的高质量流媒体传输方案,越来越多的专业机构都用上了这项技术。 偶然机遇,发现了一款NDI相关的工具Multiview Pro,让我眼前一亮。 刚开始望文生义,以为就…

css实现两个字和三个字的两端对齐

第一种实现方式&#xff1a; css设置如下&#xff1a; <!DOCTYPE html> <html lang"zh"> <head> <meta charset"UTF-8"> <title>两端对齐示例</title> <style>.name {width: 100px;text-align: justify;}.nam…

【Linux】信号|Core|Term|raise|abort|硬件异常|软件异常|signal信号

目录 ​编辑 前言 一&#xff0c;信号的概念 1.1信号的处理 1.2信号列表 1.3信号的存储 1.4查看信号 二&#xff0c;Core和Term 2.1生成Core文件 三&#xff0c;初识捕捉信号 3.1signal函数 四&#xff0c;产生信号的方式 4.1通过终端按键产生信号 4.2调用系统函…

金航标电子和萨科微半导体

金航标电子和萨科微&#xff08;www.slkormicro.com&#xff09;半导体打造有活力有创造力的团队&#xff0c;周末聚餐&#xff0c;唱歌、打球等团建活动已成为公司特色&#xff0c;一直为增强团队凝聚力和向“芯”力而贡献力量。为此&#xff0c;8月3日下午&#xff0c;kinghe…

ISO 26262中的失效率计算:IEC TR 62380-Section 15-Switches and keyboards

目录 概要 1 开关和键盘的分类 2 开关和键盘失效率的计算 2.1 Switches and keyboards 2.1.1 Base失效率 2.1.2 接触数量 2.1.3 温度循环De-rating系数 概要 IEC TR 62380《电子组件、PCBs和设备的可靠性预计通用模型》是涵盖电路、半导体分立器件、光电组件、电阻器、电…

python爬虫学习记录-请求模块urllib3

&#xff08;文章内容仅作学习交流使用&#xff09; urllib3是一个功能强大、条理清晰&#xff0c;用于HTTP客户端的第三方模块 urllib3-发送网络请求 使用urllib3发送网络请求时&#xff0c;需要先创建PoolManager对象&#xff0c;并使用该对象的request方法发送请求&#…

黑马Java零基础视频教程精华部分_17_冒泡排序、选择排序、插入排序、快速排序

系列文章目录 文章目录 系列文章目录一、冒泡排序核心思想&#xff1a;相邻的数据两两比较&#xff0c;小的放前面&#xff0c;大的放后面动图展示算法步骤代码 二、选择排序核心思想&#xff1a;不用相连的两个数据比较&#xff0c;小的放前面&#xff0c;大的放后面动图展示算…

爬虫兽问题解答1-抖音评论区爬虫采集拓客系统

总结了一些用户经常提出的问题这里记录一下方便使用 抖音视频评论拓客系统FAQ问题解答 软件服务端镇楼 问题一&#xff1a;搜索到得抖音视频评论能否永久保留随时查询 答&#xff1a;是可以得&#xff0c;通过软件中得历史记录即可查询。 问题二&#xff1a;搜索到得评论&…

Seatunnel Mysql数据同步到Mysql

环境 mysql-connector-java-8.0.28.jar、connector-cdc-mysql 配置 env {# You can set SeaTunnel environment configuration hereexecution.parallelism 2job.mode "STREAMING"# 10秒检查一次&#xff0c;可以适当加大这个值checkpoint.interval 10000#execu…