H5 Canvas 举牌小人

news2024/12/23 17:26:37

之前看到这种的举牌小人的图片觉得很有意思,最近有时间所以就尝试写写看。

在线链接
https://linyisonger.github.io/H5.Examples/?name=./080.Canvas%20%E4%B8%BE%E7%89%8C%E5%B0%8F%E4%BA%BA.html
生成效果
请添加图片描述
实现代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./assets/global.css">

    <style>
        .content {
            display: flex;
        }

        .content textarea {
            width: 300px;
            resize: none;
            border-radius: 0;
            outline: none;
            border-right-width: 0;
        }

        .content .save-btn {
            padding: 10px;
            background-color: #eefdfd;
            font-size: 15px;
            cursor: pointer;
            user-select: none;
            border-color: rgb(133, 133, 133);
            border-width: 1px; 
        }

        .content .save-btn:disabled {
            background-color: #b3b3b3;
        }
    </style>
</head>

<body>
    <div class="content">
        <textarea rows="2" placeholder="请输入需要生成的举牌文字"></textarea>

        <button class="save-btn" disabled>保存图片</button>
    </div>

    <canvas id="preview"></canvas>


    <script type="module">
        import { Randoms } from "https://gcore.jsdelivr.net/npm/@3r/tool/lib/randoms.js";

        /** @type {HTMLCanvasElement} */
        let canvas = document.querySelector("#preview")
        let ctx = canvas.getContext('2d')


        /**
         * 随机人物
         */
        function randomPerson() {
            let length = 41;
            let width = 80;
            let height = 165
            let index = Randoms.int(0, length)
            return {
                sx: index * width,
                sy: 0,
                sw: width,
                sh: height,
            }
        }

        /**
         * 绘制字符
         */
        function drawChar(char, x, y, w, h) {
            let charCenterX = x + 38
            let charCenterY = y + 28
            ctx.drawImage(image, ...Object.values(randomPerson()), x, y, w, h)
            ctx.font = '18px Helvetica'
            ctx.textAlign = "center"
            ctx.textBaseline = "middle"
            ctx.save();
            ctx.translate(charCenterX, charCenterY);
            ctx.rotate(Math.PI / 6);
            ctx.fillText(char, 0, 0)
            ctx.restore();
        }

        /**
         * 渲染文字
         * 1.分行决定渲染图片大小
         * 2.逐行偏移
         */
        function drawText(text) {
            ctx.clearRect(0, 0, canvas.width, canvas.height)

            let rows = text.split('\n')
            // 预处理
            let drawCharParams = []
            let maxX = 0;
            let maxY = 0;
            let width = 80;
            let height = 165;
            for (let i = 0; i < rows.length; i++) {
                let cols = rows[i].split('')
                let offsetX = (rows.length - i - 1) * (width / 2)
                let offsetY = i * (width / 2);
                for (let j = 0; j < cols.length; j++) {
                    const char = cols[j];
                    if (char === ' ') continue // 空字符跳过 
                    let x = j * 40 + offsetX;
                    let y = j * 15 + offsetY;
                    maxX = Math.max(maxX, x)
                    maxY = Math.max(maxY, y)
                    drawCharParams.push([char, x, y, width, height])
                }
            }
            // 更新画布大小
            canvas.setAttribute('style', `width:${maxX + width}px;height:${maxY + height}px`)
            canvas.width = canvas.clientWidth;
            canvas.height = canvas.clientHeight;
            // 处理
            for (let i = 0; i < drawCharParams.length; i++) {
                drawChar(...drawCharParams[i])
            }

        }


        let image = new Image()
        image.src = './assets/upup.png'

        let textareaDom = document.querySelector(".content textarea")
        textareaDom.addEventListener('change', (e) => {
            let text = e.target.value
            drawText(text)
        })

        let saveBtnDom = document.querySelector('.save-btn')
        saveBtnDom.addEventListener('click', (e) => {
            let a = document.createElement('a');
            a.href = window.URL.createObjectURL(base64ToBlob(canvas.toDataURL("image/png", 0.8)));
            a.setAttribute('download', '举牌小人.png');
            a.click();
        })

        image.onload = () => {
            saveBtnDom.disabled = false
        }
        // base64 转 Blob
        function base64ToBlob(base64) {
            let arr = base64.split(',');
            let mime = arr[0].match(/:(.*?);/)[1];
            let bstr = atob(arr[1]);
            let n = bstr.length;
            let u8arr = new Uint8Array(n);
            while (n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            return new Blob([u8arr], { type: mime })
        }
    </script>
</body>

</html>

在线预览
https://linyisonger.github.io/H5.Examples/
源码仓库
https://github.com/linyisonger/H5.Examples.git

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

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

相关文章

Spring Boot在医疗信息交互系统中的应用

第1章绪论 计算机已经从科研院所&#xff0c;大中型企业&#xff0c;走进了平常百姓家&#xff0c;Internet遍及世界各地&#xff0c;在网上能够用计算机进行文字草拟、修改、打印清样、文件登陆、检索、综合统计、分类、数据库管理等&#xff0c;用科学的方法将无序的信息进行…

运行第一个Java程序

准备条件&#xff1a;已经安装了Java环境 1.在桌面上的空白处单击右键&#xff0c;然后在“新建&#xff08;W&#xff09;”下拉列表中选择“文本文档”&#xff08;即左键单击“文本文档”&#xff09;# 2. 打开文本文档&#xff0c;左键单击“新建文本文档.txt - 记事本” …

Idea序列图插件-SequenceDiagram Core

&#x1f496;简介 SequenceDiagram Core 是一个 IntelliJ IDEA 插件&#xff0c;它允许开发者直接在 IDE中创建和编辑序列图&#xff08;Sequence Diagrams&#xff09;。序列图是 UML&#xff08;统一建模语言&#xff09;中的一种图表类型&#xff0c;用于描述对象之间如何…

FFmpeg的简单使用【Windows】--- 指定视频的时长

目录 功能描述 效果展示 代码实现 前端代码 后端代码 routers 》users.js routers 》 index.js app.js 功能描述 此案例是在上一个案例【FFmpeg的简单使用【Windows】--- 视频混剪添加背景音乐-CSDN博客】的基础上的进一步完善&#xff0c;可以先去看上一个案例然后再…

Scrapy | 使用Scrapy进行数据建模和请求

scrapy数据建模与请求 数据建模1.1 为什么建模1.2 如何建模1.3如何使用模板类1.4 开发流程总结 目标&#xff1a; 1.应用在scrapy项目中进行建模 2.应用构造Request对象&#xff0c;并发送请求 3.应用利用meta参数在不同的解析函数中传递数据 数据建模 | 通常在做项目的过程中…

周易解读:八卦01,八卦的卦象与记忆口诀

八卦01 在前面呢&#xff0c;我们是讲解了太极&#xff0c;两仪&#xff0c;四象的知识。这些个知识呢&#xff0c;两仪还算是比较有用一些。太极&#xff0c;四象&#xff0c;其实就是一种了解性的知识。而本节的八卦的知识&#xff0c;那可就不一样了。八卦的知识&#xff0…

nvm安装,node多版本管理

卸载nodejs win R 输入 appwiz.cpl 删除 node.js查看node.js安装路径是否有残留&#xff0c;有就删除文件夹 删除下列路径文件&#xff0c;一定要检查&#xff0c;没删干净&#xff0c;nvm安装会失败 C:\Program Files (x86)\NodejsC:\Program Files\NodejsC:\Users{User}\…

04 线性结构——栈(特性、进栈与出栈、栈顶指针、顺序栈和链式栈、相关功能的定义与代码实现)

目录 1 栈的定义 2 相关概念 2.1 栈顶&#xff08;Top&#xff09; 2.2 栈底&#xff08;Bottom&#xff09; 2.3 空栈 2.4 栈的序列 2.5 出栈入栈与栈顶指针移动的关系 2.5.1 初始情况 top -1 2.5.2 初始情况 top 0 3 栈的应用&#xff1a;函数调用 4 栈的存储结…

一个月学会Java 第17天 常用类(包装类、数学类、日期类、可变长字符串等等)

Day17 常用类(包装类、数学类、日期类、可变长字符串等等) 这一节会非常的简单和轻松&#xff0c;可以当做今天的学习就是在放松自己&#xff0c;因为这些常用类只需要记住类名和大概的方法在里面即可&#xff0c;翻一下看一下方法名都可以看出来的 目录 包装类数学类Math日期…

五、【智能体】满满干货,RAG技术在智能体中的神奇应用,你知道几个?

1. 智能问答系统 RAG技术广泛应用于问答系统中&#xff0c;特别是在需要即时获取最新信息或专业知识的场合。传统生成模型可能无法应对最新或特定领域的复杂问题&#xff0c;而RAG通过检索相关资料并增强生成过程&#xff0c;能够提供准确、具体的回答。 客户服务&#xff1a…

OpenCV-人脸检测

文章目录 一、人脸检测流程二、关键方法三、代码示例四、注意事项 OpenCV是一个开源的计算机视觉和机器学习软件库&#xff0c;它提供了多种人脸检测方法&#xff0c;以下是对OpenCV人脸检测的详细介绍&#xff1a; 一、人脸检测流程 人脸检测是识别图像中人脸位置的过程&…

2023年甘肃省职业院校技能大赛 网络建设与运维赛项 网络搭建及安全部署竞赛报告单

2023年甘肃省职业院校技能大赛 网络建设与运维赛项 网络搭建及安全部署竞赛报告单 示例&#xff1a;(仅供参考&#xff0c;具体以正式赛卷报告单为准) 在SW1上执行show vlan命令收集信息&#xff0c;截图如下&#xff1a; 请注意尽量保证格式、图片排列整齐 请注意尽量窗…

IO进程---day3

1、完成标准io的单字符实现两个文件的拷贝&#xff1b; #include<myhead.h>//标准io的单字符现两个文件的拷贝&#xff1b; int main(int argc, const char *argv[]) {//判断是否有3个文件传入if(3 ! argc){fputs("input file error\n",stderr);return -1;}//打…

测试教程分享

前几年在腾讯课堂上发布了不少课程&#xff0c;后来腾讯课堂改革&#xff0c;要收会员费&#xff0c;课程还要抽提程&#xff0c;这么下来就相当于白干了。就放弃了在上面发课程&#xff0c;再后来腾讯课堂就关闭了&#xff0c;以前发布的视频就没有地方发了&#xff0c;于是我…

IDEA中git如何快捷的使用Cherry-Pick功能

前言 我们在使用IDEA开发时&#xff0c;一般是使用GIT来管理我们的代码&#xff0c;有时候&#xff0c;我们需要在我们开发的主分支上合并其他分支的部分提交代码。注意&#xff0c;是部分&#xff0c;不是那个分支的全部提交&#xff0c;这时候&#xff0c;我们就需要使用Che…

在Linux中搭建WordPress并实现Windows主机远程访问

WordPreWordPress是一个基于PHP开发的开源平台&#xff0c;适用于在支持PHP与MySQL数据库的服务器上搭建个性化博客或网站。同时&#xff0c;它也能够作为功能强大的内容管理系统&#xff08;CMS&#xff09;被广泛应用。 虚拟机&#xff1a;VirtualBox 虚拟机安装&#x1f449…

【更新】中国地区粮食播种、粮食产量、灾害等数据(1990-2023年)

数据为中国地区粮食播种、粮食产量、灾害等数据&#xff0c;包括369个指标&#xff0c;各类农作物播种面积、粮食产量、牲畜饲养、受灾面积等。这些指标综合反映了中国农业生产、粮食安全的相关情况 一、数据介绍 数据名称&#xff1a;中国地区粮食播种、粮食产量、灾害等数据…

RHCE---使用邮箱客户端s-nail

使用邮箱客户端s-nail 方案一&#xff1a;使用网易邮箱 1&#xff0c;挂载虚拟镜像 [rootlocalhost ~]# mount /dev/sr1 /mnt mount: /mnt: /dev/sr1 already mounted on /run/media/root/RHEL-9-3-0-BaseOS-x86_64.2&#xff0c;编辑环境文件 [rootlocalhost ~]# vim /et…

部署harbor问题(缺少ssl认证证书)

在部署harbor服务&#xff0c;/install.sh启动时&#xff0c;缺少ssl认证 1. 创建证书目录 首先&#xff0c;创建 /usr/local/harbor/ssl 目录&#xff1a; mkdir -p /usr/local/harbor/ssl 2. 生成私钥 生成一个 4096 位的 RSA 私钥&#xff1a; openssl genrsa -out /us…

【优秀Python大屏】全球肺癌患病人数分析与可视化展示

1. 项目背景 肺癌是全球范围内影响人类健康的重大疾病之一&#xff0c;了解不同地区、不同收入水平国家的肺癌患病人数分布以及不同年龄段的患病趋势&#xff0c;有助于全球卫生组织和研究人员制定更有效的防治策略。本次数据分析利用全球各洲和国家的肺癌患病数据&#xff0c…