JavaScript使用渐变来美化对象!

news2024/10/4 10:33:36

我们的目标是渐变!渐变!

        首先了解,渐变分为线性渐变和径向渐变,线性渐变可以是从左上角到右下角的渐变,径向渐变是从中心向外的渐变。

        JavaScript中实现渐变可以使用addColorStop的方法,例如创建一个线性渐变的代码为:

// 创建线性渐变
var linearGradient = ctx.createLinearGradient(0, 0, 200, 0);
linearGradient.addColorStop("0", "green");
linearGradient.addColorStop("1", "white");

// 应用渐变到矩形
ctx.fillStyle = linearGradient;
ctx.fillRect(10, 10, 180, 80);

        我们使用createLinearGradient(x1, y1, x2, y2)创建一个线性渐变。参数定义了渐变的开始和结束位置。

        径向渐变也是类似的:

// 创建径向渐变
var radialGradient = ctx.createRadialGradient(100, 50, 10, 100, 50, 50);
radialGradient.addColorStop("0", "red");
radialGradient.addColorStop("0.5", "yellow");
radialGradient.addColorStop("1", "green");

// 应用渐变到矩形
ctx.fillStyle = radialGradient;
ctx.fillRect(10, 10, 180, 80);

        使用createRadialGradient(x1, y1, r1, x2, y2, r2)创建一个径向渐变。参数定义了内外圆的位置和半径。

        接下去我希望区分填充渐变和描边渐变,并且把这些代码写在一个函数里。创建drawCircle函数,包括circle和isFill参数,传入一个圆,如果isFill为true则填充,否则描边。

function drawCircle(circle, isFill) {
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");

    // 创建径向渐变
    var radialGradient = ctx.createRadialGradient(circle.x, circle.y, 0, circle.x, circle.y, circle.radius);
    radialGradient.addColorStop("0", "red");
    radialGradient.addColorStop("0.5", "yellow");
    radialGradient.addColorStop("1", "green");

    if (isFill) {
        // 应用渐变填充
        ctx.fillStyle = radialGradient;
        ctx.beginPath();
        ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
        ctx.fill();
    } else {
        // 应用渐变描边
        ctx.strokeStyle = radialGradient;
        ctx.lineWidth = 10; // 可以根据需要调整线宽
        ctx.beginPath();
        ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
        ctx.stroke();
    }
}

// 圆的参数
var circle = {
    x: 100,
    y: 100,
    radius: 50
};

// 画一个填充的圆
drawCircle(circle, true);

// 画一个描边的圆
// drawCircle(circle, false);

        不过,这个代码只实现了径向渐变,有兴趣可以在这里停下来自己实现一下填充渐变。完成的代码如下:

function drawCircle(circle, isFill, gradientType) {
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");

    // 根据渐变类型创建渐变
    var gradient;
    if (gradientType === 'linear') {
        // 创建线性渐变
        gradient = ctx.createLinearGradient(circle.x, circle.y - circle.radius, circle.x + circle.radius, circle.y + circle.radius);
        gradient.addColorStop("0", "red");
        gradient.addColorStop("1", "green");
    } else if (gradientType === 'radial') {
        // 创建径向渐变
        gradient = ctx.createRadialGradient(circle.x, circle.y, 0, circle.x, circle.y, circle.radius);
        gradient.addColorStop("0", "red");
        gradient.addColorStop("0.5", "yellow");
        gradient.addColorStop("1", "green");
    }

    if (isFill) {
        // 应用渐变填充
        ctx.fillStyle = gradient;
    } else {
        // 应用渐变描边
        ctx.strokeStyle = gradient;
        ctx.lineWidth = 10; // 可以根据需要调整线宽
    }

    ctx.beginPath();
    ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
    if (isFill) {
        ctx.fill();
    } else {
        ctx.stroke();
    }
}

// 圆的参数
var circle = {
    x: 100,
    y: 100,
    radius: 50
};

// 画一个填充的线性渐变圆
drawCircle(circle, true, 'linear');

// 画一个描边的径向渐变圆
// drawCircle(circle, false, 'radial');

拆分函数:

        此时我们发现,这个drawCircle函数已经很大了,为了项目的可拓展性和可维护性,我们应该进行一下区分。

function createLinearGradient(ctx, circle) {
    return ctx.createLinearGradient(0, 0, circle.x * 2, circle.y * 2);
}

function createRadialGradient(ctx, circle) {
    return ctx.createRadialGradient(circle.x, circle.y, 0, circle.x, circle.y, circle.radius);
}

function applyGradient(ctx, gradient, isFill) {
    if (isFill) {
        ctx.fillStyle = gradient;
    } else {
        ctx.strokeStyle = gradient;
        ctx.lineWidth = 10; // 可以根据需要调整线宽
    }
}

function drawCircleWithGradient(ctx, circle, isFill, gradient) {
    ctx.beginPath();
    ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2);
    if (isFill) {
        ctx.fill();
    } else {
        ctx.stroke();
    }
}

function drawCircle(circle, isFill, gradientType) {
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");

    var gradient;
    if (gradientType === 'linear') {
        gradient = createLinearGradient(ctx, circle);
        gradient.addColorStop("0", "red");
        gradient.addColorStop("1", "green");
    } else if (gradientType === 'radial') {
        gradient = createRadialGradient(ctx, circle);
        gradient.addColorStop("0", "red");
        gradient.addColorStop("0.5", "yellow");
        gradient.addColorStop("1", "green");
    }

    applyGradient(ctx, gradient, isFill);
    drawCircleWithGradient(ctx, circle, isFill, gradient);
}

// 圆的参数
var circle = {
    x: 200,
    y: 200,
    radius: 100
};

// 画一个填充的线性渐变圆
drawCircle(circle, true, 'linear');

// 画一个描边的径向渐变圆
// drawCircle(circle, false, 'radial');

拆分为四个函数: 

        createLinearGradient: 创建线性渐变。

        createRadialGradient: 创建径向渐变。

        applyGradient: 应用渐变到填充或描边。

        drawCircleWithGradient: 使用给定的渐变绘制圆。

        drawCircle 函数: 根据传入的 gradientType 参数调用相应的函数创建渐变。

代码的拓展

        上面我们已经初步实现了一个圆的渐变,但是也许还可以传入正方形?矩形?三角形?甚至是更多的类型?

        首先需要来实现这几种类型:

// 绘制圆形
function drawCircle(ctx, x, y, radius, isFill) {
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    ctx.fill();
    ctx.stroke();
}

// 绘制矩形
function drawRect(ctx, x, y, width, height, isFill) {
    ctx.beginPath();
    ctx.rect(x, y, width, height);
    ctx.fill();
    ctx.stroke();
}

// 绘制三角形
function drawTriangle(ctx, x1, y1, x2, y2, x3, y3, isFill) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.lineTo(x3, y3);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();
}

        绘制的时候,就要根据形状来选择分支。我们创建函数drawShape:

// 绘制形状
function drawShape(ctx, shape, isFill) {
    let gradient;
    switch (shape.type) {
        case 'circle':
            gradient = createRadialGradient(ctx, shape.x, shape.y, shape.radius);
            applyGradient(ctx, gradient, isFill);
            drawCircle(ctx, shape.x, shape.y, shape.radius, isFill);
            break;
        case 'rect':
            gradient = createLinearGradient(ctx, 0, 0, shape.width, shape.height);
            applyGradient(ctx, gradient, isFill);
            drawRect(ctx, shape.x, shape.y, shape.width, shape.height, isFill);
            break;
        case 'triangle':
            gradient = createLinearGradient(ctx, shape.x1, shape.y1, shape.x3, shape.y3);
            applyGradient(ctx, gradient, isFill);
            drawTriangle(ctx, shape.x1, shape.y1, shape.x2, shape.y2, shape.x3, shape.y3, isFill);
            break;
        // 可以添加更多形状
    }
}

         布豪!发现圆形的渐变似乎有问题!我们来修改一下,并且我们发现js文件已经太大了,我们来拆分一下,下面给出一个完整案例:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas 绘图示例</title>
    <!-- 引用外部CSS -->
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <canvas id="myCanvas" width="600" height="600">
            您的浏览器不支持 HTML5 Canvas 标签。
        </canvas>
    </div>

    <!-- 引用外部JavaScript文件 -->
    <script src="js/gradients.js"></script>
    <script src="js/shapes.js"></script>
    <script src="js/main.js"></script>
</body>
</html>
/* styles.css */

body {
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
    background-color: #f0f0f0;
}

.container {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

canvas {
    border: 2px solid #000;
    background-color: #fff;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
// gradients.js

// 创建线性渐变
function createLinearGradient(ctx, x1, y1, x2, y2) {
    const gradient = ctx.createLinearGradient(x1, y1, x2, y2);
    gradient.addColorStop(0, "red");
    gradient.addColorStop(1, "green");
    return gradient;
}

// 创建径向渐变
function createRadialGradient(ctx, x, y, r) {
    const gradient = ctx.createRadialGradient(x, y, 0, x, y, r);
    gradient.addColorStop(0, "red");
    gradient.addColorStop(0.5, "yellow");
    gradient.addColorStop(1, "green");
    return gradient;
}

// shapes.js

// 应用渐变
function applyGradient(ctx, gradient, isFill) {
    if (isFill) {
        ctx.fillStyle = gradient;
    } else {
        ctx.strokeStyle = gradient;
        ctx.lineWidth = 5; // 可以根据需要调整线宽
    }
}

// 绘制圆形
function drawCircle(ctx, x, y, radius, isFill) {
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI * 2);
    if (isFill) {
        ctx.fill();
    } else {
        ctx.stroke();
    }
}

// 绘制矩形
function drawRect(ctx, x, y, width, height, isFill) {
    ctx.beginPath();
    ctx.rect(x, y, width, height);
    if (isFill) {
        ctx.fill();
    } else {
        ctx.stroke();
    }
}

// 绘制三角形
function drawTriangle(ctx, x1, y1, x2, y2, x3, y3, isFill) {
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.lineTo(x3, y3);
    ctx.closePath();
    if (isFill) {
        ctx.fill();
    } else {
        ctx.stroke();
    }
}

// 绘制形状
function drawShape(ctx, shape, isFill) {
    let gradient;
    switch (shape.type) {
        case 'circle':
            gradient = createRadialGradient(ctx, shape.x, shape.y, shape.radius);
            applyGradient(ctx, gradient, isFill);
            drawCircle(ctx, shape.x, shape.y, shape.radius, isFill);
            break;
        case 'rect':
            gradient = createLinearGradient(ctx, shape.x, shape.y, shape.x + shape.width, shape.y + shape.height);
            applyGradient(ctx, gradient, isFill);
            drawRect(ctx, shape.x, shape.y, shape.width, shape.height, isFill);
            break;
        case 'triangle':
            gradient = createLinearGradient(ctx, shape.x1, shape.y1, shape.x3, shape.y3);
            applyGradient(ctx, gradient, isFill);
            drawTriangle(ctx, shape.x1, shape.y1, shape.x2, shape.y2, shape.x3, shape.y3, isFill);
            break;
        // 可以添加更多形状
        default:
            console.warn(`未知的形状类型: ${shape.type}`);
    }
}

 

// main.js

// 确保所有依赖的脚本已经加载
window.addEventListener('DOMContentLoaded', () => {
    // 获取Canvas上下文
    const canvas = document.getElementById("myCanvas");
    if (!canvas.getContext) {
        console.error("浏览器不支持 Canvas!");
        return;
    }
    const ctx = canvas.getContext("2d");

    // 定义要绘制的形状
    const shapes = [
        { type: 'circle', x: 300, y: 300, radius: 100, isFill: true },
        { type: 'rect', x: 150, y: 150, width: 200, height: 100, isFill: false },
        { type: 'triangle', x1: 50, y1: 50, x2: 150, y2: 50, x3: 100, y3: 150, isFill: false }
    ];

    // 绘制所有形状
    shapes.forEach(shape => {
        drawShape(ctx, shape, shape.isFill);
    });
});

 这个项目已经初步搭建了一个有意思的canvas页面,当然我希望它更有意思!

main.js文件上的花活

我们只需要修改main.js文件即可,我们使用随机循环等方式创建各类对象:

// main.js

// 确保所有依赖的脚本已经加载
window.addEventListener('DOMContentLoaded', () => {
    // 获取Canvas上下文
    const canvas = document.getElementById("myCanvas");
    if (!canvas.getContext) {
        console.error("浏览器不支持 Canvas!");
        return;
    }
    const ctx = canvas.getContext("2d");

    // 随机颜色生成函数
    function getRandomColor() {
        const letters = '0123456789ABCDEF';
        let color = '#';
        for (let i = 0; i < 6; i++) {
            color += letters[Math.floor(Math.random() * 16)];
        }
        return color;
    }

    // 定义循环生成形状的函数
    function generateShapes() {
        const shapes = [];

        // 生成圆形:随机大小和位置,大小范围拉大
        for (let i = 0; i < 100; i++) {
            const radius = 1 + Math.random() * 30;  // 随机大小,30-130
            const x = Math.random() * (canvas.width - radius * 2) + radius;
            const y = Math.random() * (canvas.height - radius * 2) + radius;
            shapes.push({ type: 'circle', x, y, radius, isFill: true, color: getRandomColor() });
        }

        // 生成矩形:随机旋转,渐变颜色,大小和位置随机
        for (let i = 0; i < 30; i++) {
            const width = 60 + Math.random() * 40;
            const height = 40 + Math.random() * 30;
            const x = Math.random() * (canvas.width - width);
            const y = Math.random() * (canvas.height - height);
            const angle = Math.random() * Math.PI;  // 随机旋转角度
            shapes.push({ type: 'rect', x, y, width, height, isFill: false, angle });
        }

        // 生成三角形:顶点随机,颜色随机
        for (let i = 0; i < 20; i++) {
            const x1 = Math.random() * canvas.width;
            const y1 = Math.random() * canvas.height;
            const x2 = x1 + Math.random() * 100;
            const y2 = y1 + Math.random() * 100;
            const x3 = x1 + Math.random() * 50;
            const y3 = y1 - Math.random() * 100;
            shapes.push({ type: 'triangle', x1, y1, x2, y2, x3, y3, isFill: true, color: getRandomColor() });
        }

        return shapes;
    }

    // 获取生成的形状
    const shapes = generateShapes();

    // 绘制所有形状
    shapes.forEach(shape => {
        // 如果是矩形,先旋转后绘制
        if (shape.type === 'rect') {
            ctx.save();
            ctx.translate(shape.x + shape.width / 2, shape.y + shape.height / 2);
            ctx.rotate(shape.angle);
            ctx.translate(-(shape.x + shape.width / 2), -(shape.y + shape.height / 2));
            drawShape(ctx, shape, shape.isFill);
            ctx.restore();
        } else if (shape.type === 'triangle') {
            ctx.fillStyle = shape.color;  // 使用随机颜色填充三角形
            drawShape(ctx, shape, shape.isFill);
        } else if (shape.type === 'circle') {
            ctx.fillStyle = shape.color;  // 使用随机颜色填充圆形
            drawShape(ctx, shape, shape.isFill);
        }
    });
});

        当然,这个项目看上去依然存在问题,还可以进一步拓展等,更多奇妙的故事等你自己去探索吧~

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

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

相关文章

高性能防静电主轴4033 AC-ESD 在线路板切割中的非凡表现

随着电子产品的日益小型化/集成化&#xff0c;线路板的制造也面临着更高的挑战。线路板分板作为电子制造流程中的关键环节&#xff0c;其效率和精度直接影响到最终产品的质量和市场竞争力。因此专用的高性能防静电主轴SycoTec 4033 AC-ESD凭借其卓越的性能&#xff0c;成为众多…

多系统萎缩患者必知的营养补充指南

亲爱的朋友们&#xff0c;今天我们要聊的是一个较为少见但影响深远的疾病——多系统萎缩&#xff08;Multiple System Atrophy, MSA&#xff09;。这是一种成年期发病的神经系统退行性疾病&#xff0c;给患者的日常生活带来了诸多不便。但别担心&#xff0c;通过合理的营养补充…

JAVA开源项目 旅游管理系统 计算机毕业设计

本文项目编号 T 063 &#xff0c;文末自助获取源码 \color{red}{T063&#xff0c;文末自助获取源码} T063&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析5.4 用例设计 六、核…

QGIS中怎么裁剪与掩膜提取

最近&#xff0c;我接到了一个关于QGIS中矢量与栅格与栅格数据怎么裁剪与掩膜提取到自己想要区域的咨询。 其实这个操作&#xff0c;与arcgis中的操作其实是类似的 下面是我对这个问题的解决思路&#xff1a; 首先得把栅格与矢量数据加载进去&#xff0c;如下图&#xff1a;…

基于SSM的农家乐预约系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【JavaEE】——CAS指令和ABA问题

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;CAS指令 1&#xff1a;概念 2&#xff1a;伪代码例子说明 3&#xff1a;优点 二&am…

《向量数据库指南》——Mlivus Cloud:优惠大放送,向量数据库新体验

哈哈,各位向量数据库领域的探索者和实践者们,大家好!我是大禹智库的向量数据库高级研究员王帅旭,也是《向量数据库指南》的作者,今天咱们来聊聊Mlivus Cloud这个让人眼前一亮的向量数据库服务。特别是它那诱人的优惠放送,简直是给咱们这些热衷于技术创新的朋友们送上了一…

微信小程序使用picker,数组怎么设置默认值

默认先显示请选择XXX。然后点击弹出选择列表。如果默认value是0的话&#xff0c;他就直接默认显示数组的第一个了。<picker mode"selector" :value"planIndex" :range"planStatus" range-key"label" change"bindPlanChange&qu…

一些 Go Web 开发笔记

原文&#xff1a;Julia Evans - 2024.09.27 在过去的几周里&#xff0c;我花了很多时间在用 Go 开发一个网站&#xff0c;虽然不知道它最终会不会发布&#xff0c;但在这个过程中我学到了一些东西&#xff0c;想记录下来。以下是我的一些收获&#xff1a; Go 1.22 现在有了更…

【ubuntu】ubuntu20.04 install vscode

1.download Visual Studio Code - Code Editing. Redefined download .deb. 2.install or intsall by ternimal: sudo dpkg -i code_1.93.1-1726079302_amd64.deb 3.open vscode 4. install some extensions c , python or GitLens.

SpringMVC2~~~

数据格式化 提交数据(比如表单)&#xff0c;对提交的数据进行转换和处理 基本数据类型可以和字符串自动转换 <a href"<%request.getContextPath()%>/addMonsterUI">添加妖怪</a> Controller Scope(value "prototype") public class …

spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)

文章目录 【README】【1】文件上传与MultipartResolver【1.1】使用MultipartResolver进行文件上传【1.2】springmvc处理multipart多部件请求流程【1.3】使用springmvc上传文件代码实现&#xff08;springmvc6.10版本&#xff09;&#xff1a; 【2】Handler与HandlerAdaptor&…

遮罩解决图片悬浮操作看不到的情况

未悬浮效果 悬浮效果 如果仅仅是添加绝对定位&#xff0c;那么遇到白色图片&#xff0c;就会看不到白色字体。通过遮罩&#xff08;绝对定位透明度&#xff09;就可以解决这个问题。 <script setup> </script><template><div class"box"><…

protobuf 讲解

一、序列化概念回顾 二、什么是PB 将结构化数据进行序列化的一种方式 三、PB的特点 语言无关、平台无关&#xff1a;即PB支持Java&#xff0c;C、Python等多种语言。支持多个平台 高效&#xff1a;即比XML更小&#xff0c;更快&#xff0c;更为简单。 扩展性、兼容性好&am…

MATLAB使用眼图分析QPSK通信系统接收端匹配滤波后的信号

文章目录 前言一、MATLAB仿真代码二、仿真结果 前言 本文完成以下内容&#xff1a; &#xff08;1&#xff09;建立一个QPSK传输系统&#xff0c;并引入EsNo20dB&#xff08;SNR0dB&#xff09;的噪声&#xff0c;接收端对带噪信号进行匹配滤波。 &#xff08;2&#xff09;分…

Python并发编程挑战与解决方案

Python并发编程挑战与解决方案 并发编程是现代软件开发中的一项核心能力&#xff0c;它允许多个任务同时运行&#xff0c;提高程序的性能和响应速度。Python因其易用性和灵活性而广受欢迎&#xff0c;但其全局解释器锁&#xff08;GIL&#xff09;以及其他特性给并发编程带来了…

CSS实现服务卡片

CSS实现服务卡片 效果展示 CSS 知识点 回顾整体CSS知识点灵活运用CSS知识点 页面整体布局 <div class"container"><div class"card"><div class"box"><div class"icon"><ion-icon name"color-pal…

python集合set

1、集合是无序的&#xff0c;所以集合不支持下标访问索引 2、集合的常见操作 3、集合内不允许重复元素 4、注意

若依cloud升级mybaits-plus方法

1、在主pom文件中引入依赖 <!-- mybatis-plus 增强CRUD --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency> 2、在ruoyi-comm…

基于大数据的Python+Django电影票房数据可视化分析系统设计与实现

目录 1 引言 2 系统需求分析 3 技术选型 4 系统架构设计 5 关键技术实现 6 系统实现 7 总结与展望 1 引言 随着数字媒体技术的发展&#xff0c;电影产业已经成为全球经济文化不可或缺的一部分。电影不仅是艺术表达的形式&#xff0c;更是大众娱乐的重要来源。在这个背景…