【Canvas与艺术】绘制灰色橄榄枝环绕“Premium Quality”徽章

【关键点】

利用复数计算出树叶的控制点,用二次贝塞尔曲线勾画树叶。

【成果图】

【代码】

<!DOCTYPE html>
<html lang="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<head>
     <title>灰色橄榄枝环绕Premium Quality徽章</title>
     <style type="text/css">
     .centerlize{
        margin:0 auto;
        width:1200px;
     }
     </style>
     </head>

     <body οnlοad="init();">
        <div class="centerlize">
            <canvas id="myCanvas" width="12px" height="12px" style="border:1px dotted black;">
                如果看到这段文字说您的浏览器尚不支持HTML5 Canvas,请更换浏览器再试.
            </canvas>
            <img id="myImg" src="116-1.jpg" style="display:none;"/>
            <img id="myImg2" src="116-2.jpg" style="display:none;"/>
        </div>
     </body>
</html>
<script type="text/javascript">
<!--
/*****************************************************************
* 将全体代码(从<!DOCTYPE到script>)拷贝下来,粘贴到文本编辑器中,
* 另存为.html文件,再用chrome浏览器打开,就能看到实现效果。
******************************************************************/

// canvas的绘图环境
var ctx;

// 高宽
const WIDTH=512;
const HEIGHT=512;

// 舞台对象
var stage;

//-------------------------------
// 初始化
//-------------------------------
function init(){
    // 获得canvas对象
    var canvas=document.getElementById('myCanvas');  
    canvas.width=WIDTH;
    canvas.height=HEIGHT;

    // 初始化canvas的绘图环境
    ctx=canvas.getContext('2d');  
    ctx.translate(WIDTH/2,HEIGHT/2);// 原点平移到画布中央

    // 准备
    stage=new Stage();    
    stage.init();

    // 开幕
    animate();
}

// 播放动画
function animate(){    
    stage.update();    
    stage.paintBg(ctx);
    stage.paintFg(ctx);     

    // 循环
    if(true){
        window.requestAnimationFrame(animate);   
    }
}

// 舞台类
function Stage(){
    // 初始化
    this.init=function(){
        
    }

    // 更新
    this.update=function(){
        
    }

    // 画背景
    this.paintBg=function(ctx){
        ctx.clearRect(-WIDTH/2,-HEIGHT/2,WIDTH,HEIGHT);// 清屏    

        // 外轮廓
        var gearArr=getGearArray(48,Math.PI/48,252,230);                
        ctx.beginPath();
        for(var i=0;i<gearArr.length;i++){
            ctx.lineTo(gearArr[i].x,gearArr[i].y);
        }
        ctx.closePath();
        ctx.lineWidth=0.5;
        ctx.strokeStyle="rgb(83,93,105)";
        ctx.stroke();

        // 48齿圈
        gearArr=getGearArray(48,Math.PI/48,250,228);                
        ctx.beginPath();
        for(var i=0;i<gearArr.length;i++){
            ctx.lineTo(gearArr[i].x,gearArr[i].y);
        }
        ctx.closePath();
        ctx.fillStyle="rgb(83,93,105)";
        ctx.fill();

        // 第一道白圈
        ctx.beginPath();
        ctx.arc(0,0,218,0,Math.PI*2,true);
        ctx.closePath();
        ctx.lineWidth=2;
        ctx.strokeStyle="white";
        ctx.stroke();

        // 第二道白圈
        ctx.beginPath();
        ctx.arc(0,0,210,0,Math.PI*2,true);
        ctx.closePath();
        ctx.lineWidth=2;
        ctx.strokeStyle="white";
        ctx.stroke();

        // --------右半圈橄榄枝
        // 半圆
        const radius=170;
        const leaveLength=40;
        ctx.beginPath();
        ctx.arc(0,0,radius,Math.PI*(-3/2)-Math.PI/20,Math.PI*(-1/2)+Math.PI/20,true);
        ctx.lineWidth=1;
        ctx.strokeStyle="white";
        ctx.stroke();
    
        // 外侧叶子
        for(var i=1;i<20;i++){
            var ratio=(i+30)/60;

            var theta=-Math.PI/2+i*Math.PI/20;
            var start={};
            start.x=radius*Math.cos(theta);
            start.y=radius*Math.sin(theta);

            var end1={};
            end1.x=start.x+ratio*leaveLength*Math.cos(-Math.PI/4+theta);
            end1.y=start.y+ratio*leaveLength*Math.sin(-Math.PI/4+theta);

            var center={};
            center.x=(start.x+end1.x)/2;
            center.y=(start.y+end1.y)/2;

            // 利用复数求c1
            var c1={};
            c1.x=center.x+center.y-end1.y;
            c1.y=end1.x-center.x+center.y;

            // 利用复数求c2
            var c2={};
            c2.x=center.x+center.y-start.y;
            c2.y=start.x-center.x+center.y;

            ctx.beginPath();
            ctx.lineTo(start.x,start.y);    
            ctx.quadraticCurveTo(c1.x,c1.y,end1.x,end1.y);
            ctx.quadraticCurveTo(c2.x,c2.y,start.x,start.y);
            ctx.closePath();
            ctx.fillStyle="white";
            ctx.fill();
        }

        // 内侧叶子
        for(var i=1;i<20;i++){
            var ratio=(i+30)/60;

            var theta=-Math.PI/2+i*Math.PI/20;
            var start={};
            start.x=radius*Math.cos(theta);
            start.y=radius*Math.sin(theta);

            var end1={};
            end1.x=start.x+ratio*leaveLength*Math.cos(-Math.PI/4*3+theta);
            end1.y=start.y+ratio*leaveLength*Math.sin(-Math.PI/4*3+theta);

            var center={};
            center.x=(start.x+end1.x)/2;
            center.y=(start.y+end1.y)/2;

            // 利用复数求c1
            var c1={};
            c1.x=center.x+center.y-end1.y;
            c1.y=end1.x-center.x+center.y;

            // 利用复数求c2
            var c2={};
            c2.x=center.x+center.y-start.y;
            c2.y=start.x-center.x+center.y;

            ctx.beginPath();
            ctx.lineTo(start.x,start.y);    
            ctx.quadraticCurveTo(c1.x,c1.y,end1.x,end1.y);
            ctx.quadraticCurveTo(c2.x,c2.y,start.x,start.y);
            ctx.closePath();
            ctx.fillStyle="white";
            ctx.fill();
        }

        // --------左半圈橄榄枝
        // 半圆
        ctx.beginPath();
        ctx.arc(0,0,radius,Math.PI*(-1/2)-Math.PI/20,Math.PI*(-3/2)+Math.PI/20,true);
        ctx.lineWidth=1;
        ctx.strokeStyle="white";
        ctx.stroke();
    
        // 外侧叶子
        for(var i=1;i<20;i++){
            var ratio=(i+30)/60;

            var theta=-Math.PI/2-i*Math.PI/20;
            var start={};
            start.x=radius*Math.cos(theta);
            start.y=radius*Math.sin(theta);

            var end1={};
            end1.x=start.x+ratio*leaveLength*Math.cos(Math.PI/4+theta);
            end1.y=start.y+ratio*leaveLength*Math.sin(Math.PI/4+theta);

            var center={};
            center.x=(start.x+end1.x)/2;
            center.y=(start.y+end1.y)/2;

            // 利用复数求c1
            var c1={};
            c1.x=center.x+center.y-end1.y;
            c1.y=end1.x-center.x+center.y;

            // 利用复数求c2
            var c2={};
            c2.x=center.x+center.y-start.y;
            c2.y=start.x-center.x+center.y;

            ctx.beginPath();
            ctx.lineTo(start.x,start.y);    
            ctx.quadraticCurveTo(c1.x,c1.y,end1.x,end1.y);
            ctx.quadraticCurveTo(c2.x,c2.y,start.x,start.y);
            ctx.closePath();
            ctx.fillStyle="white";
            ctx.fill();
        }

        // 内侧叶子
        for(var i=1;i<20;i++){
            var ratio=(i+30)/60;

            var theta=Math.PI/2*3-i*Math.PI/20;
            var start={};
            start.x=radius*Math.cos(theta);
            start.y=radius*Math.sin(theta);

            var end1={};
            end1.x=start.x+ratio*leaveLength*Math.cos(Math.PI/4*3+theta);
            end1.y=start.y+ratio*leaveLength*Math.sin(Math.PI/4*3+theta);

            var center={};
            center.x=(start.x+end1.x)/2;
            center.y=(start.y+end1.y)/2;

            // 利用复数求c1
            var c1={};
            c1.x=center.x+center.y-end1.y;
            c1.y=end1.x-center.x+center.y;

            // 利用复数求c2
            var c2={};
            c2.x=center.x+center.y-start.y;
            c2.y=start.x-center.x+center.y;

            ctx.beginPath();
            ctx.lineTo(start.x,start.y);    
            ctx.quadraticCurveTo(c1.x,c1.y,end1.x,end1.y);
            ctx.quadraticCurveTo(c2.x,c2.y,start.x,start.y);
            ctx.closePath();
            ctx.fillStyle="white";
            ctx.fill();
        } 

        // 上方大五角星
        draw5Star(ctx,0,-100,20,"white");

        // Premium Quality文字
        ctx.textBaseline="bottom";
        ctx.textAlign="center";
        ctx.font = "40px Stencil Std";
        ctx.fillStyle="white";
        ctx.fillText("PREMIUM",0,-20);
        ctx.fillText("QUALITY",0,40);

        // 一圈五角星
        for(var i=0;i<5;i++){
            var theta=Math.PI/8*i+Math.PI/180*45;
            var x=100*Math.cos(theta);
            var y=100*Math.sin(theta);

            ctx.save();
            ctx.translate(x,y);
            ctx.rotate(theta-Math.PI/2);
            draw5Star(ctx,0,0,12,"white");
            ctx.restore();
        }

        // 汉字优
        ctx.textBaseline="bottom";
        ctx.textAlign="center";
        ctx.font = "28px 方正宋刻本秀楷简体";
        ctx.fillStyle="white";
        ctx.fillText("优",0,183);

        // 作者
        ctx.textBaseline="bottom";
        ctx.textAlign="center";
        ctx.font = "8px consolas";
        ctx.fillStyle="black";
        ctx.fillText("逆火原创",WIDTH/2-40,HEIGHT/2-10);
    }

    // 画前景
    this.paintFg=function(ctx){
        
    }
}

//-------------------------------------------------------
// 取得一个齿轮全部控制点的函数
// n:齿轮齿数
// angle:齿斜面倾角
// outerRadius:齿轮外径
// innerRadius:齿轮内径
//-------------------------------------------------------
function getGearArray(n,angle,outerRadius,innerRadius){
    // 准备齿轮数组
    var gearArr=new Array();

    for(var i=0;i<n*2;i++){
        var alpha=Math.PI/n*i;
        var bata=alpha+angle;
        var x1,y1,x2,y2;
        
        if(i%2==1){
            x1=innerRadius*Math.cos(alpha);
            y1=innerRadius*Math.sin(alpha);

            x2=outerRadius*Math.cos(bata);
            y2=outerRadius*Math.sin(bata);                
        }else{                
            x1=outerRadius*Math.cos(alpha);
            y1=outerRadius*Math.sin(alpha);

            x2=innerRadius*Math.cos(bata);
            y2=innerRadius*Math.sin(bata);
        }

        gearArr.push({x:x1,y:y1});
        gearArr.push({x:x2,y:y2});
    }

    return gearArr;
}

// 画实心五角星的函数
function draw5Star(ctx,x,y,r,color){
    ctx.save()
    ctx.translate(x-r,y-r);    
    ctx.beginPath();
    ctx.moveTo(r, 0);
    ctx.lineTo(r+Math.cos(Math.PI*3/10)*r, r+Math.sin(Math.PI*3/10)*r);
    ctx.lineTo(r-Math.cos(Math.PI*1/10)*r, r-Math.sin(Math.PI*1/10)*r);
    ctx.lineTo(r+Math.cos(Math.PI*1/10)*r, r-Math.sin(Math.PI*1/10)*r);
    ctx.lineTo(r-Math.cos(Math.PI*3/10)*r, r+Math.sin(Math.PI*3/10)*r);
    ctx.lineTo(r, 0);
    ctx.closePath();
    ctx.fillStyle=color;
    ctx.fill();
    ctx.restore();
}

/*---------------------------------------------
活着不是靠泪水博得同情,
而是靠汗水赢得掌声。
理性的羊肠小道,胜过鲁莽的高速公路。
----------------------------------------------*/
//-->
</script>

END

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

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

相关文章

海外语言任务商城源码 海外仓库系统及商城系统

海外语言任务商城源码 海外仓库系统及商城系统 自带利息宝理财活动文本搭建教程 搭建简单&#xff0c;前台是单语言的。 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89013345 更多资源下载&#xff1a;关注我。

【.Net】DotNetty

文章目录 概述NIO和BIO、AIODotNetty适用场景DotNetty的整体架构和模块DotNetty的使用示例来源 概述 本系列文章主要讲述由微软Azure团队研发的.net的版本的netty&#xff0c;Dotnetty。所有的开发都将基于.net core 3.1版本进行开发。 Dotnetty是什么&#xff0c;原本Netty是…

wordpress全站开发指南-面向开发者及深度用户(全中文实操)--wordpress中的著名循环

wordpress中的著名循环 首先&#xff0c;在深入研究任何代码之前&#xff0c;我们首先要确保我们有不止一篇博客文章可以工作。因此&#xff0c;我们要去自己的wordpress站点&#xff0c;从侧边栏单机Posts(文章)&#xff0c;进行创建 在执行代码的时候会优先执行single.php如…

第四百四十二回 再谈flutter_launcher_icons包

文章目录 1. 概念介绍2. 使用方法3. 示例代码4. 经验与总结4.1 经验分享4.2 内容总结 我们在上一章回中介绍了"overlay_tooltip简介"相关的内容&#xff0c;本章回中将 再谈flutter_launcher_icons包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 …

sqlmap(四)案例

一、注入DB2 http://124.70.71.251:49431/new_list.php?id1 这是墨者学院里的靶机&#xff0c;地址&#xff1a;https://www.mozhe.cn/ 1.1 测试数据库类型 python sqlmap.py -u "http://124.70.71.251:49431/new_list.php?id1" 1.2 测试用户权限类型 查询选…

WCH恒沁单片机-CH32V307学习记录2----FreeRTOS移植

RISC-V 单片机 FreeRTOS 移植 前面用了 5 篇博客详细介绍了 FreeRTOS 在 ARM Cortex-M3 MCU 上是如何运行的。 FreeRTOS从代码层面进行原理分析系列 现在我直接用之前的 RISC-V MCU 开发板子&#xff08;CH32V307VCT6&#xff09;再次对 FreeRTOS 进行移植&#xff0c;其实也…

深度学习理论基础(六)Transformer多头注意力机制

目录 一、自定义多头注意力机制1. 缩放点积注意力&#xff08;Scaled Dot-Product Attention&#xff09;● 计算公式● 原理 2. 多头注意力机制框图● 具体代码 二、pytorch中的子注意力机制模块 深度学习中的注意力机制&#xff08;Attention Mechanism&#xff09;是一种模仿…

html骨架以及常见标签

推荐一个网站mdn。 html语法 双标签&#xff1a;<标签 属性"属性值">内容</标签> 属性&#xff1a;给标签提供附加信息。大多数属性以键值对的形式存在。如果属性名和属性值一样&#xff0c;可以致谢属性值。 单标签&#xff1a;<标签 属性"属…

【JavaWeb】Day33.MySQL概述

什么是数据库 数据库&#xff1a;英文为 DataBase&#xff0c;简称DB&#xff0c;它是存储和管理数据的仓库。 像我们日常访问的电商网站京东&#xff0c;企业内部的管理系统OA、ERP、CRM这类的系统&#xff0c;以及大家每天都会刷的头条、抖音类的app&#xff0c;那这些大家所…

Python | Leetcode Python题解之第13题罗马数字转整数

题目&#xff1a; 题解&#xff1a; class Solution:SYMBOL_VALUES {I: 1,V: 5,X: 10,L: 50,C: 100,D: 500,M: 1000,}def romanToInt(self, s: str) -> int:ans 0n len(s)for i, ch in enumerate(s):value Solution.SYMBOL_VALUES[ch]if i < n - 1 and value < S…

.NET8 和 Vue.js 的前后端分离

在.NET 8中实现前后端分离主要涉及到两个部分&#xff1a;后端API的开发和前端应用的开发。后端API通常使用ASP.NET Core来构建&#xff0c;而前端应用则可以使用任何前端框架或技术栈&#xff0c;比如Vue.js、React或Angular等。下面是一个简化的步骤指南&#xff0c;帮助你在…

物联网系统设计 8

1 规划中小型LoRa 中小型分时复用&#xff0c;大型项目需要学习LoRaWAN 1.1 通信记录 1.2 节点能耗 1278芯片 满功率20DMB&#xff0c;增加PA&#xff0c;发送功率 30 DBM 内置天线柔性 棒状 3db 203 休眠、发生、接收 计算链路预算&#xff0c;工作电流&#xff0c;工…

Node.JS多线程PromisePool之promise-pool库实现

什么是Promise Pool Map-like, concurrent promise processing for Node.js. Promise-Pool是一个用于管理并发请求的JavaScript库&#xff0c;它可以限制同时进行的请求数量&#xff0c;以避免过多的请求导致服务器压力过大。使用Promise-Pool可以方便地实现对多个异步操作的并…

Mysql中的 IFNULL 函数的详解

Mysql中的 IFNULL 函数的详解 概念 在mysql中IFNULL() 函数用于判断第一个表达式是否为 NULL&#xff0c;如果第一个值不为NULL就执行第一个值。第一个值为 NULL 则返回第二个参数的值。 语法 IFNULL(a, b)Demo 举例说明 创建表 create table student_one( sno varchar(20)…

Day106:代码审计-PHP原生开发篇文件安全上传监控功能定位关键搜索1day挖掘

目录 emlog-文件上传&文件删除 emlog-模板文件上传 emlog-插件文件上传 emlog-任意文件删除 通达OA-文件上传&文件包含 知识点&#xff1a; PHP审计-原生开发-文件上传&文件删除-Emlog PHP审计-原生开发-文件上传&文件包含-通达OA emlog-文件上传&文件…

HUD抬头显示器阳光倒灌实验一般步骤

概述 汽车HUD&#xff08;Head-Up Display&#xff0c;即抬头显示器&#xff09;阳光倒灌实验是一种用于评估汽车抬头显示器在阳光直射条件下显示效果的测试。该实验的目的是确保HUD系统在强烈的阳光下依然能够清晰地显示信息&#xff0c;不影响驾驶员的视线和驾驶安全。 一般…

单链表经典oj题 (一) 简单

1.删除指定节点数据&#xff08;非尾节点&#xff09;&#xff0c;要求时间复杂度为O(1) . - 力扣&#xff08;LeetCode&#xff09; 在之前我们将单链表删除指定节点的操作是先遍历找到pos的前一个结点&#xff0c;然后再进行删除&#xff0c;但是现在要求再O(1)时间内完成&am…

博客部署001-centos安装docker

1、安装docker 1.1 卸载旧版本的 Docker sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine1.2 设置 Docker 仓库 安装 Docker Engine 之前&#xff0c;首先需要设置…

力扣Lc29---- 541. 反转字符串 II(java版)-2024年4月06日

1.题目描述 2.知识点 &#xff08;1&#xff09;执行步骤如下&#xff1a; 初始化 s “abcdefg” 和 k 2 将字符串分割成长度为 2k 4 的块。 对每个块中的前 k 2 个字符进行反转。 执行过程 1&#xff09;第一次循环&#xff08;i 0&#xff09; start 0 end Math.min(0…

心法利器[112] | 考古RAG-20年RAG概念提出的论文

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2023年新的文章合集已经发布&#xff0c;获取方式看这里&#xff1a;又添十万字-CS的陋室2023年文章合集来袭&#xff0c;更…