JavaScript练习——文本与图形

要求实现下面这个效果

观察图片,我们的需求如下:

  1. 准备画布和上下文:在开始绘制之前,需要有一个HTML5 <canvas> 元素,并且获取其绘图上下文(context),这是进行绘图操作的基础。

  2. 定义形状和样式:对于想要绘制的每个形状(文本、矩形、圆形),需要定义它们的位置、尺寸和样式。这通常涉及到创建包含这些属性的对象。

  3. 编写绘制函数:需要编写或使用现有的函数来绘制这些形状。这些函数通常会接受上下文和形状的属性作为参数,并使用Canvas API进行绘制。

  4. 添加视觉效果:增强视觉效果,添加阴影和渐变色。这通常涉及到使用Canvas API中的阴影和渐变相关方法。

  5. 组合元素:将所有的绘制操作组合在一起,形成一个完整的绘图流程。确保每一步都按照正确的顺序执行,以实现预期的视觉效果。

function drawCanvas() {
    // 设置文本位置
    var text = {
        x: canvas.width / 2,
        y: canvas.height / 2
    };
    drawText(context, text, 1, 64);

    // 设置矩形位置和尺寸
    var rect = {
        x: canvas.width / 2 - 35,
        y: canvas.height / 2 - 40,
        h: 70,
        w: 70
    };
    drawRectPath(context, rect, 1);

    // 设置圆形位置和半径
    var circle = {
        x: canvas.width / 2,
        y: canvas.height / 2 - 5,
        r: 80,
        clockwise: false
    };
    drawCirclePath(context, circle, 0, 1);

    // 添加阴影效果
    putShadowOnPath(context, "yellow", 10, -10, 20);

    // 创建并应用渐变色
    var grd = createLinearGradient(context, 150, 150, canvas.width - 150, canvas.height - 150, colors);
    putColorOnPath(context, grd, 1, 5);
}

上面的代码提供了一个框架,具体的每个函数实现还需要更进一步设计,我将提供一些参考:

/**
 * 绘制文本
 * @author zjvivi
 * @version 1.0
 * @buildDate 2024-9-22
 * @param {Object} context 绘制的目标context
 * @param {Object} text 包括字体及大小的font,起始点水平对齐align,起始点垂直基线baseline,起始点坐标(x,y)等信息
 * @param {String} style 填充色/描边色/其他样式
 * @param {Number} isFill 是否填充,true/1表示填充,反之描边
 * @param {Number} lineWidth 绘制线条的宽度
 */
function drawText(context,text,isFill,lineWidth) {
    context.font=`${text.fontSize}px ${text.font}` ; //设置字体大小
    context.textAlign=text.align;
    context.textBaseline=text.baseline;
    if(isFill){
        context.fillStyle=text.style;
        context.fillText(text.text, text.x,text.y); //绘制填充文本
    }else{
        context.strokeStyle=text.style;
        context.lineWidth=lineWidth || 1;
        context.strokeText(text.text, text.x,text.y); //绘制描边文本
    }
}
/**
 * 绘制矩形路径
 * @author zjvivi
 * @version 1.0
 * @buildDate 2024-9-22
 * @param {Object} context 绘制的目标context
 * @param {Object} rect 包括绘制起始点坐标(x,y)、宽度width和高度height信息
 * @param {*} isNewPath 是否开启新路径  是否开启新路径,true/1表示开启,反之不开启
 */
function drawRectPath(context,rect,isNewPath) {
   if(isNewPath) context.beginPath();
   context.rect(rect.x, rect.y, rect.w, rect.h);
}
/**
 * 绘制圆形路径
 * @author zjvivi
 * @version 1.0
 * @buildDate 2024-9-22
 * @param {Object} context 绘制的目标context
 * @param {Object} cirle包括绘制圆心坐标(x,y)、半径r、起始弧度startAngle、终止弧度endAngle和是否顺时针clockwise信息
 * @param {Boolean} isNewPath 是否开启新路径  是否开启新路径,true/1表示开启,反之不开启
 * @param {Boolean} isClosePath 是否闭合路径 true/1表示闭合,反之不闭合
 */
function drawCirclePath(context,circle,isNewPath,isClosePath){
    if(isNewPath) context.beginPath();
    context.arc(circle.x,circle.y,circle.r,circle.sAngle,circle.eAngle,!circle.clockwise);
    if(isClosePath) context.closePath();
}
/**
 * 设置路径阴影
 * @author zjvivi
 * @version 1.0
 * @buildDate 2024-9-22
 * @param {Object} context 绘制的目标canvas
 * @param {String} color  阴影颜色
 * @param {*} offsetX 
 * @param {*} offsetY 
 * @param {*} blur 
 */
function putShadowOnPath(context,color,offsetX,offsetY,blur) {
    if(blur!==undefined) context.shadowBlur=blur;
    if(color!==undefined) context.shadowColor=color;
    if(offsetX!==undefined) context.shadowOffsetX=offsetX;
    if(offsetY!==undefined) context.shadowOffsetY=offsetY;
    
}
/**
 * 创建线性渐变对象
 * @author zjvivi
 * @version 1.0
 * @buildDate 2024-9-22
 * @param {*} context 绘制目标context对象
 * @param {*} x1  起始点的x坐标
 * @param {*} y1  起始点的y坐标
 * @param {*} x2  终止点的x坐标
 * @param {*} y2  终止点的x坐标
 * @param {*} colors 颜色数组colors=[{pos:0,color:'orange'},...]
 * @returns 
 */
function createLinearGradient(context,x1,y1,x2,y2,colors){
    let grd=context.createLinearGradient(x1, y1, x2, y2);
   
    for(let i=0;i<colors.length;i++){
        grd.addColorStop(colors[i].pos, colors[i].color);
    }
    return grd;  
}
/**
 * 设置路径样式
 * @author zjvivi
 * @version 1.0
 * @buildDate 2024-9-22
 * @param {Object} context 绘制的目标context
 * @param {String} style 填充色/描边色/其他样式
 * @param {Number} isFill  是否填充,true/1表示填充,反之描边
 * @param {Number} lineWidth 绘制线条的宽度
 */
function putColorOnPath(context,style,isFill,lineWidth) {
    if(isFill){
        context.fillStyle=style;
        context.fill(); 
    }else{
        context.strokeStyle=style;
        context.lineWidth=lineWidth || 1;
        context.stroke();
    }
}

        这些函数被设计为通用函数,可作为函数库在后续开发中使用。将html,js代码都结合起来就可以实现前文的图形效果了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[ubuntu]编译共享内存读取出现read.c:(.text+0x1a): undefined reference to `shm_open‘问题解决方案

问题log /tmp/ccByifPx.o: In function main: read.c:(.text0x1a): undefined reference to shm_open read.c:(.text0xd9): undefined reference to shm_unlink collect2: error: ld returned 1 exit status 程序代码 #include <stdio.h> #include <stdlib.h> #…

【redis】哈希类型详解

哈希类型详解 一、哈希类型的介绍二、哈希类型的常用命令2.1 HSET2.2 HGET2.3 HEXISTS2.4 HDEL2.5 HKEYS2.6 HAVLS2.7 HGETALL2.8 HMGET2.9 HLEN2.10 HSETNX2.11 HINCRBY2.12 HINCRBYFLOAT 三、哈希类型命令小结四、哈希类型内部编码五、哈希类型应用场景 一、哈希类型的介绍 …

单片机GPIO的8种工作模式

1、输入 GPIO_MODE_AIN:模拟输入 GPIO_MODE_IN_FLOATING:浮空输入 GPIO_MODE_IPD:下拉输入 GPIO_MODE_IPU:上拉输入 2、输出 GPIO_MODE_OUT_OD:开漏输出&#xff08;特殊情况使用&#xff09; GPIO_MODE_OUT_PP&#xff1a;推挽输出-----点灯&#xff08;通用&#…

YOLO-World解读:零基础学习开放世界模型

文章目录 一、摘要二、引言相关工作方法预训练公式模型架构可重新参数化的视觉-语言路径聚合网络&#xff08;RepVL-PAN&#xff09; 3.4 预训练方案 实验YOLO-World: 利用多样化数据集进行开放词汇对象检测的预训练方法YOLO-World: LVIS数据集上的零样本性能评估YOLO-World: 预…

深入理解下oracle 11g block组成

深层次说&#xff0c;oracle数据库的最少组成单位应该是块&#xff0c;一般默认情况下&#xff0c;oracle数据库的块大小是8kb&#xff0c;其中存储着我们平常所需的数据。我们在使用过程中&#xff0c;难免会疑问道&#xff1a;“oracle数据块中到底是怎样组成的&#xff0c;平…

《智慧教育实时数据分析推荐项目》详细分析

一、项目介绍 1、背景介绍 在互联网、移动互联网的带动下&#xff0c;教育逐渐从线下走向线上&#xff0c;在线教育近几年一直处于行业的风口浪尖&#xff0c;那随着基础设施的不断完善&#xff0c;用户需求也发生不少变化&#xff0c;因此传统教育机构、新兴互联网企业都在探…

stable-diffusion-webui 安装

一、安装 Python 3.11.8 (略) 二、下载stable-diffusion-webui cd E:\AITOOLS git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 下载完成后&#xff1a; cd E:\AITOOLS\stable-diffusion-webui #运行 webui-user.bat 我们会发现要下载一下&#xff1a…

【Seed-Labs 2.0】The Kaminsky Attack Lab

说在前面 本实验属为Seed-Labs 的DNS LAB 中的第二个实验&#xff0c;是第一个实验的延伸&#xff0c;从攻击者和受害者同一个LAN中变成不在同一个LAN中&#xff0c;该系列一共有五个实验: Local DNS Attack LabThe Kaminsky Attack LabDNS Rebinding Attack LabDNS Infrastr…

类的实例化

文章目录 一、实例化2.1 实例化概念 一、实例化 2.1 实例化概念 用类类型在物理内存中创建对象的过程&#xff0c;称为类实例化出对象。 类是对象进行⼀种抽象描述&#xff0c;是⼀个模型⼀样的东西&#xff0c;限定了类有哪些成员变量&#xff0c;这些成员变量只是声明&…

《图像梯度与常见算子全解析:原理、用法及效果展示》

简介:本文深入探讨图像梯度相关知识&#xff0c;详细介绍图像梯度是像素灰度值在不同方向的变化速度&#xff0c;并以 “pig.JPG” 图像为例&#xff0c;通过代码展示如何选取图像部分区域并分析其像素值以论证图像梯度与边缘信息的关联。接着全面阐述了 Sobel 算子&#xff0c…

解决IDEA报包不存在,但实际存在的问题

前言 最近在把一个亿老项目交割给同事&#xff0c;同事在导入项目运行时遇到IDEA报包不存在&#xff0c;但实际存在的问题&#xff0c;最终通过以下方式解决 现象 在IDEA里启动运行项目&#xff0c;报某个类有问题&#xff0c;引入的包不存在。 点击这个引入的包&#xff0c;可…

C++(进阶) 第1章 继承

C&#xff08;进阶) 第1章 继承 文章目录 前言一、继承1.什么是继承2.继承的使用 二、继承方式1.private成员变量的&#xff08;3种继承方式&#xff09;继承2. private继承方式3.继承基类成员访问⽅式的变化 三、基类和派生类间的转换1.切片 四、 继承中的作⽤域1.隐藏规则&am…

resnet50,clip,Faiss+Flask简易图文搜索服务

一、实现 文件夹目录结构&#xff1a; templates -----upload.html faiss_app.py 前端代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widt…

SFP+光模块介绍

SFP光模块介绍 1 SFP光模块简介(Small Form -Factor Pluggable)2 光模块管脚定义 1 SFP光模块简介(Small Form -Factor Pluggable) 光模块&#xff08;Optical Module&#xff09;由光电子器件、功能电路和光接口等组成&#xff0c;光电子器件包括激光发射器(Laser Transmitte…

Redis——Raft算法

Raft使用较为广泛的强一致性、去中心化、高可用的分布式协议&#xff0c;即使在网络、节点故障等情况下&#xff0c;多个节点依然能达到一致性。 其中redis、etcd等都用到了这种算法 在Redis集群中&#xff0c;采取的主从复制结构&#xff0c;当主节点宕机后&#xff0c;哨兵会…

【网络系统管理】2023年全国职业院校技能大赛:组策略--10套题组合--3

11、阻止Microsoft账户登录 (1)计算机配置\策略\Windows设置\安全设置\本地策略\安全选项 12、允许更改系统时间 (1)计算机配置\策略\Windows设置\安全设置\本地策略\用户权限分配 13、可以登录本机的用户 (1)计算机配置\策略\Windows设置\安全设置\本地策略\用户权限…

Glide源码学习

前言 开始 基本使用非常简单&#xff0c;链式调用把context对象传入&#xff0c;设置要加载的URL&#xff0c;设置要填充的ImageView控件&#xff0c;方法很简洁&#xff0c;每次都是传入的最核心的参数&#xff0c;底层加载的缓存逻辑&#xff0c;加载的引擎&#xff0c;加载…

基于RFSOC实现LFMCW雷达测距测速

雷达原理可以参考以下文章 https://zhuanlan.zhihu.com/p/508764579 一般情况下&#xff0c;雷达发射信号的模型可采用线性调频连续波&#xff08;LFMCW&#xff09; &#xff0c;发射波形的信号形式为调频连续锯齿波。线性调频的含义即调制信号频率随时间线性变化&#xff0c…

VELO SkyOW+坐垫,一起Cityride温暖你的上海之旅

随着冬季的到来&#xff0c;上海的街头巷尾弥漫着一种独特的浪漫气息&#xff0c;当金黄的落叶从空中飘落&#xff0c;铺满路边&#xff0c;只是路过就仿佛骑进了一幅世界名画。无论是沿着外滩漫游&#xff0c;还是穿行在浦东的高楼间&#xff0c;骑行的方式总能让你充分体验到…

基于lora的llama2二次预训练

基于lora的llama2二次预训练 一、为什么需要对llama2做基于lora的二次预训练? 加入中文训练语料进行llama2的二次预训练&#xff0c;这样模型就可以增加支持中文输出的能力。 二、基于lora的llama2二次预训练的目标是什么&#xff1f; 在保持预训练模型权重不变的情况下&a…