HTML5 火焰字体效果教程

这里写目录标题

  • HTML5 火焰字体效果教程
    • 前言
    • 项目概述
    • 基本原理
    • 项目结构
    • 详细实现步骤
      • 1. HTML结构
      • 2. CSS样式
      • 3. JavaScript实现
    • 代码详解
      • 1. 初始化设置
      • 2. 粒子系统
      • 3. 生成粒子
      • 4. 动画循环
      • 5. 交互控制
    • 扩展和优化建议
    • 总结
    • 完整代码

前言

在这篇教程中,我们将一步步学习如何使用HTML5 Canvas和JavaScript创建一个逼真的火焰字体效果。这个效果可以让文字看起来像是被火焰包围,非常炫酷!
在这里插入图片描述

项目概述

我们的火焰字体效果具有以下特点:

  • 可以自定义文字内容
  • 可以调整火焰强度
  • 可以选择不同的火焰颜色
  • 响应式设计,适配不同屏幕尺寸

基本原理

这个效果的核心原理是使用粒子系统来模拟火焰。具体来说:

  1. 我们先在Canvas上绘制文字
  2. 然后获取文字的像素数据
  3. 在文字像素的位置生成火焰粒子
  4. 让这些粒子向上飘动并逐渐消失,模拟火焰效果

项目结构

我们的项目包含三个主要文件:

  • index.html: 页面结构
  • styles.css: 样式表
  • fire.js: JavaScript代码实现火焰效果

详细实现步骤

1. HTML结构

首先,我们需要创建基本的HTML结构:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>HTML5 逼真火焰字体效果</title><link rel="stylesheet" href="styles.css">
</head>
<body><div class="container"><h1 class="title">调整下面输入框中的文字</h1><input type="text" id="textInput" value="火焰文字" maxlength="20"><div class="canvas-wrapper"><canvas id="fireCanvas"></canvas></div><div class="controls"><label for="intensitySlider">火焰强度:</label><input type="range" id="intensitySlider" min="1" max="10" value="5"><label for="colorSelect">火焰颜色:</label><select id="colorSelect"><option value="red">红色</option><option value="blue">蓝色</option><option value="green">绿色</option><option value="purple">紫色</option></select></div></div><script src="fire.js"></script>
</body>
</html>

这个HTML结构包含:

  • 一个标题
  • 一个文本输入框,用于输入要显示的文字
  • 一个Canvas元素,用于绘制火焰效果
  • 控制元素:火焰强度滑块和颜色选择下拉菜单

2. CSS样式

接下来,我们添加CSS样式让页面看起来更美观:

* {margin: 0;padding: 0;box-sizing: border-box;
}body {font-family: 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;background-color: #111;color: #fff;display: flex;justify-content: center;align-items: center;min-height: 100vh;overflow: hidden;
}.container {display: flex;flex-direction: column;align-items: center;max-width: 800px;width: 100%;padding: 20px;
}.title {margin-bottom: 20px;text-align: center;color: #f8f8f8;text-shadow: 0 0 10px rgba(255, 165, 0, 0.7);
}#textInput {padding: 10px 15px;font-size: 18px;width: 300px;text-align: center;margin-bottom: 20px;background-color: #333;border: 1px solid #555;color: #fff;border-radius: 5px;
}.canvas-wrapper {width: 100%;height: 200px;margin: 20px 0;display: flex;justify-content: center;align-items: center;
}#fireCanvas {background-color: transparent;max-width: 100%;
}.controls {display: flex;flex-wrap: wrap;justify-content: center;align-items: center;gap: 15px;margin-top: 20px;
}label {margin-right: 5px;
}input[type="range"] {width: 150px;height: 8px;background: #333;outline: none;border-radius: 5px;
}select {padding: 5px 10px;background-color: #333;color: #fff;border: 1px solid #555;border-radius: 5px;
}

这些CSS样式主要是:

  • 设置了深色背景
  • 居中显示内容
  • 美化输入框、滑块和下拉菜单
  • 设置Canvas容器的尺寸

3. JavaScript实现

最后也是最重要的部分,我们通过JavaScript实现火焰效果:

document.addEventListener('DOMContentLoaded', () => {// 获取DOM元素const canvas = document.getElementById('fireCanvas');const ctx = canvas.getContext('2d');const textInput = document.getElementById('textInput');const intensitySlider = document.getElementById('intensitySlider');const colorSelect = document.getElementById('colorSelect');// 设置画布尺寸function resizeCanvas() {canvas.width = window.innerWidth > 800 ? 800 : window.innerWidth - 40;canvas.height = 200;}// 初始化参数let particles = [];let fireIntensity = 5;let fireColor = 'red';let text = textInput.value;let animationId;// 粒子类class Particle {constructor(x, y) {this.x = x;this.y = y;this.vx = Math.random() * 2 - 1;  // 水平速度this.vy = -2 - Math.random() * 3; // 垂直速度(向上)this.size = Math.random() * 3 + 2;  // 粒子大小this.life = Math.random() * 80 + 50; // 粒子生命值this.maxLife = this.life;}update() {// 粒子逐渐上升并左右摆动this.x += this.vx * (fireIntensity / 5);this.y += this.vy * (fireIntensity / 5);// 随机左右飘动效果this.vx += (Math.random() * 0.4 - 0.2);this.vx = Math.min(Math.max(this.vx, -1.5), 1.5);// 粒子生命值减少this.life--;// 粒子逐渐缩小if (this.size > 0.2) {this.size -= 0.05;}}draw() {if (this.life <= 0) return;// 透明度根据生命周期变化const opacity = this.life / this.maxLife;// 根据选择的颜色创建渐变let gradient;if (fireColor === 'red') {gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.size);gradient.addColorStop(0, `rgba(255, 255, 255, ${opacity})`);gradient.addColorStop(0.4, `rgba(255, 180, 0, ${opacity})`);gradient.addColorStop(0.8, `rgba(255, 0, 0, ${opacity * 0.8})`);gradient.addColorStop(1, `rgba(0, 0, 0, 0)`);} else if (fireColor === 'blue') {// 蓝色火焰渐变gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.size);gradient.addColorStop(0, `rgba(255, 255, 255, ${opacity})`);gradient.addColorStop(0.4, `rgba(0, 150, 255, ${opacity})`);gradient.addColorStop(0.8, `rgba(0, 50, 255, ${opacity * 0.8})`);gradient.addColorStop(1, `rgba(0, 0, 0, 0)`);} else if (fireColor === 'green') {// 绿色火焰渐变gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.size);gradient.addColorStop(0, `rgba(255, 255, 255, ${opacity})`);gradient.addColorStop(0.4, `rgba(0, 255, 150, ${opacity})`);gradient.addColorStop(0.8, `rgba(0, 180, 0, ${opacity * 0.8})`);gradient.addColorStop(1, `rgba(0, 0, 0, 0)`);} else if (fireColor === 'purple') {// 紫色火焰渐变gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.size);gradient.addColorStop(0, `rgba(255, 255, 255, ${opacity})`);gradient.addColorStop(0.4, `rgba(200, 100, 255, ${opacity})`);gradient.addColorStop(0.8, `rgba(128, 0, 255, ${opacity * 0.8})`);gradient.addColorStop(1, `rgba(0, 0, 0, 0)`);}// 绘制粒子ctx.fillStyle = gradient;ctx.beginPath();ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);ctx.fill();}}// 生成粒子function generateParticles() {// 设置字体大小(根据文本长度自适应)const fontSize = Math.floor(canvas.width / (text.length * 1.5));const finalFontSize = Math.min(Math.max(fontSize, 30), 80);ctx.font = `bold ${finalFontSize}px '微软雅黑', Arial`;ctx.textAlign = 'center';ctx.textBaseline = 'middle';// 测量文本尺寸const textMetrics = ctx.measureText(text);const textWidth = textMetrics.width;// 临时画布用于测量字体像素const tempCanvas = document.createElement('canvas');const tempCtx = tempCanvas.getContext('2d');tempCanvas.width = textWidth + 20;tempCanvas.height = finalFontSize * 1.5;tempCtx.font = ctx.font;tempCtx.textAlign = 'center';tempCtx.textBaseline = 'middle';tempCtx.fillStyle = '#ffffff';tempCtx.fillText(text, tempCanvas.width / 2, tempCanvas.height / 2);// 获取像素数据const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);const pixels = imageData.data;// 清空现有粒子particles = [];// 根据像素数据创建粒子for (let y = 0; y < tempCanvas.height; y += Math.max(1, Math.floor(5 / (fireIntensity / 5)))) {for (let x = 0; x < tempCanvas.width; x += Math.max(1, Math.floor(5 / (fireIntensity / 5)))) {const index = (y * tempCanvas.width + x) * 4;if (pixels[index + 3] > 128) { // 只在非透明像素处创建粒子const particleX = (canvas.width - textWidth) / 2 + x;const particleY = (canvas.height - finalFontSize) / 2 + y;// 每个点有一定几率生成粒子if (Math.random() < 0.3) {particles.push(new Particle(particleX, particleY));}}}}}// 动画循环function animate() {ctx.clearRect(0, 0, canvas.width, canvas.height);// 帧率控制let newParticles = [];// 更新和绘制现有粒子for (let i = 0; i < particles.length; i++) {particles[i].update();particles[i].draw();// 保留还有生命值的粒子if (particles[i].life > 0) {newParticles.push(particles[i]);}}// 更新粒子数组particles = newParticles;// 持续生成新粒子if (particles.length < 500 * (fireIntensity / 5)) {generateParticles();}// 继续动画循环animationId = requestAnimationFrame(animate);}// 初始化function init() {resizeCanvas();text = textInput.value;fireIntensity = parseInt(intensitySlider.value);fireColor = colorSelect.value;// 重新生成粒子generateParticles();// 如果已经有动画在运行,先取消if (animationId) {cancelAnimationFrame(animationId);}// 开始动画animate();}// 事件监听window.addEventListener('resize', () => {resizeCanvas();init();});textInput.addEventListener('input', () => {text = textInput.value;init();});intensitySlider.addEventListener('input', () => {fireIntensity = parseInt(intensitySlider.value);});colorSelect.addEventListener('change', () => {fireColor = colorSelect.value;});// 启动动画init();
});

代码详解

1. 初始化设置

首先,我们在页面加载完成后获取所有需要的DOM元素,并设置初始参数:

document.addEventListener('DOMContentLoaded', () => {// 获取DOM元素const canvas = document.getElementById('fireCanvas');const ctx = canvas.getContext('2d');const textInput = document.getElementById('textInput');const intensitySlider = document.getElementById('intensitySlider');const colorSelect = document.getElementById('colorSelect');// 初始化参数let particles = [];let fireIntensity = 5;let fireColor = 'red';let text = textInput.value;let animationId;// 设置画布尺寸function resizeCanvas() {canvas.width = window.innerWidth > 800 ? 800 : window.innerWidth - 40;canvas.height = 200;}

2. 粒子系统

火焰效果的核心是粒子系统。我们创建了一个Particle类来表示每个火焰粒子:

class Particle {constructor(x, y) {this.x = x;this.y = y;this.vx = Math.random() * 2 - 1;  // 水平速度this.vy = -2 - Math.random() * 3; // 垂直速度(向上)this.size = Math.random() * 3 + 2;  // 粒子大小this.life = Math.random() * 80 + 50; // 粒子生命值this.maxLife = this.life;}update() {// 粒子逐渐上升并左右摆动this.x += this.vx * (fireIntensity / 5);this.y += this.vy * (fireIntensity / 5);// 随机左右飘动效果this.vx += (Math.random() * 0.4 - 0.2);this.vx = Math.min(Math.max(this.vx, -1.5), 1.5);// 粒子生命值减少this.life--;// 粒子逐渐缩小if (this.size > 0.2) {this.size -= 0.05;}}draw() {// 绘制粒子的代码...}
}

每个粒子都有:

  • 位置(x, y)
  • 速度(vx, vy)
  • 大小(size)
  • 生命值(life)

粒子会随时间上升、左右飘动、变小并最终消失。

3. 生成粒子

我们需要根据文字形状生成粒子。这是通过以下步骤实现的:

  1. 在一个临时Canvas上绘制文字
  2. 获取文字的像素数据
  3. 在文字像素的位置创建粒子
function generateParticles() {// 设置字体大小const fontSize = Math.floor(canvas.width / (text.length * 1.5));const finalFontSize = Math.min(Math.max(fontSize, 30), 80);ctx.font = `bold ${finalFontSize}px '微软雅黑', Arial`;// 测量文本尺寸const textMetrics = ctx.measureText(text);const textWidth = textMetrics.width;// 创建临时画布const tempCanvas = document.createElement('canvas');const tempCtx = tempCanvas.getContext('2d');tempCanvas.width = textWidth + 20;tempCanvas.height = finalFontSize * 1.5;// 在临时画布上绘制文字tempCtx.font = ctx.font;tempCtx.textAlign = 'center';tempCtx.textBaseline = 'middle';tempCtx.fillStyle = '#ffffff';tempCtx.fillText(text, tempCanvas.width / 2, tempCanvas.height / 2);// 获取像素数据const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);const pixels = imageData.data;// 根据像素数据创建粒子for (let y = 0; y < tempCanvas.height; y += Math.max(1, Math.floor(5 / (fireIntensity / 5)))) {for (let x = 0; x < tempCanvas.width; x += Math.max(1, Math.floor(5 / (fireIntensity / 5)))) {const index = (y * tempCanvas.width + x) * 4;if (pixels[index + 3] > 128) { // 只在非透明像素处创建粒子const particleX = (canvas.width - textWidth) / 2 + x;const particleY = (canvas.height - finalFontSize) / 2 + y;// 每个点有一定几率生成粒子if (Math.random() < 0.3) {particles.push(new Particle(particleX, particleY));}}}}
}

这里的关键是我们只在文字的非透明像素位置创建粒子,并且根据火焰强度调整粒子的密度。

4. 动画循环

最后,我们需要一个动画循环来更新和绘制所有粒子:

function animate() {ctx.clearRect(0, 0, canvas.width, canvas.height);let newParticles = [];// 更新和绘制现有粒子for (let i = 0; i < particles.length; i++) {particles[i].update();particles[i].draw();// 保留还有生命值的粒子if (particles[i].life > 0) {newParticles.push(particles[i]);}}// 更新粒子数组particles = newParticles;// 持续生成新粒子if (particles.length < 500 * (fireIntensity / 5)) {generateParticles();}// 继续动画循环animationId = requestAnimationFrame(animate);
}

在每一帧中,我们:

  1. 清除Canvas
  2. 更新和绘制所有粒子
  3. 移除已经"死亡"的粒子
  4. 如果粒子数量不足,生成新粒子
  5. 请求下一帧动画

5. 交互控制

我们添加了事件监听器来实现交互控制:

// 事件监听
window.addEventListener('resize', () => {resizeCanvas();init();
});textInput.addEventListener('input', () => {text = textInput.value;init();
});intensitySlider.addEventListener('input', () => {fireIntensity = parseInt(intensitySlider.value);
});colorSelect.addEventListener('change', () => {fireColor = colorSelect.value;
});

这样用户就可以:

  • 修改文字内容
  • 调整火焰强度
  • 更改火焰颜色

扩展和优化建议

如果你想进一步改进这个效果,可以考虑:

  1. 添加更多颜色选项:可以创建更多种类的火焰颜色,甚至是彩虹渐变效果

  2. 添加背景音效:可以添加火焰燃烧的音效,增强沉浸感

  3. 优化性能:对于移动设备,可以自动降低粒子数量以提高性能

  4. 添加更多文字效果:比如文字闪烁、扭曲等效果

  5. 保存功能:允许用户保存火焰文字效果为图片或GIF

总结

通过这个项目,我们学习了:

  1. 如何使用HTML5 Canvas绘制图形
  2. 如何创建和管理粒子系统
  3. 如何使用requestAnimationFrame实现平滑动画
  4. 如何获取和处理Canvas的像素数据
  5. 如何实现用户交互控制

希望这个教程对你有所帮助!现在,你可以根据自己的需要修改和扩展这个火焰字体效果了。

完整代码

完整代码可以在本项目的GitHub仓库中找到:[https://github.com/hhse/Html]

如果你有任何问题或建议,欢迎在评论区留言!

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SMOTE-XGBoost实战:金融风控中欺诈检测的样本不平衡解决方案

1. 行业问题背景 &#xff08;1&#xff09;金融欺诈检测的特殊性 在支付风控领域&#xff0c;样本不平衡是核心痛点。Visa 2023年度报告显示&#xff0c;全球信用卡欺诈率约为0.6%&#xff0c;但单笔欺诈交易平均损失高达$500。传统机器学习模型在此场景下表现堪忧&#xff1…

Instagram下载保存 -下载狗解析工具

在日常浏览Instagram时&#xff0c;是否有过这样的烦恼&#xff1a;看到一个精彩的视频&#xff0c;想要保存下来&#xff0c;却不知道如何操作&#xff1f;有时候我们会看到一些特别的旅行视频、搞笑片段&#xff0c;甚至是喜欢的名人分享的内容&#xff0c;简直是舍不得错过。…

flink如何基于Pekko实现RPC调用

摘要 通过阅读flink源码&#xff0c;了解flink是如何基于Pekko实现远程RPC调用的 Pekko实现远程调用 Flink 的 RPC 框架底层是构建在 Pekko 的 actor 模型之上的&#xff0c;了解Pekko如何使用&#xff0c;对后续源码的阅读有帮助。 Apache Pekko&#xff08;原为 Akka 的一…

Kafka节点注册冲突问题分析与解决

一、核心错误分析 ERROR Error while creating ephemeral at /brokers/ids/1, node already exists and owner does not match org.apache.zookeeper.KeeperException$NodeExistsException: KeeperErrorCode NodeExists问题本质&#xff1a;ZooKeeper中已存在ID为1的broker节…

突破PPO训练效率瓶颈!字节跳动提出T-PPO,推理LLM训练速度提升2.5倍

突破PPO训练效率瓶颈&#xff01;字节跳动提出T-PPO&#xff0c;推理LLM训练速度提升2.5倍 在大语言模型&#xff08;LLM&#xff09;通过长思维链&#xff08;CoT&#xff09;展现出强大推理能力的当下&#xff0c;强化学习&#xff08;RL&#xff09;作为关键技术却面临训练…

【Python】dictionary

1 字典功能 字典是可变容器模型&#xff0c;且可存储任意类型对象&#xff1b; 字典的每个键值对 <key: value> 用冒号 : 分割&#xff0c;每个对之间用逗号(,)分割&#xff0c;整个字典包括在花括号 {} 中 ,格式如下所示&#xff1a; d {key1 : value1, key2 : value…

【python】If 语句

1 使用if 进行条件判断 1.1 检查字符串是否相等 car bmw car BMW # FALSEcar bmw car.upper() BMW # true # 变小写用方法&#xff1a;lower1.2 检查字符串是否不相等 my_car yadeaif my_car ! Audi:print("Buy one! Buy one! Buy one!")1.3 比较数字 answe…

Knife4j 使用详解

一、概述 Knife4j 是一款基于 Swagger 的开源 API 文档工具&#xff0c;旨在为 Java 开发者提供更美观、功能更强大的 API 文档生成、展示和调试体验。它是 Swagger-Bootstrap-UI 的升级版&#xff0c;通过增强 UI 界面和扩展功能&#xff0c;解决了原生 Swagger UI 界面简陋、…

Java excel坐标计算

package com.common.base.util.excel;/*** excel 坐标计算*/ public class UtilExcelPosi {/*** deepseek生成 ExcelProperty(index UtilExcelPosi.pA)*/public final static int pA 0;public final static int pB 1;public final static int pC 2;public final static i…

【JavaWeb】Servlet+JSP 实现分页功能

文章目录 思路数据抽出功能设计 功能模块工具类前端内容用户端数据处理 思路 数据抽出 需要显示的数据&#xff0c;查询的数据抽出&#xff1b;进行分页显示&#xff0c;需要统计抽出的件数&#xff0c;然后根据页面显示尺寸调整显示页面内容&#xff1b; 功能设计 翻页需要…

SpringBoot-准备工作-工程搭建

目录 1.创建空项目 2.检查项目jdk版本 3.检查Maven的全局配置 4.配置项目的字符集 5.创建SpringBoot工程 1.创建空项目 2.检查项目jdk版本 3.检查Maven的全局配置 4.配置项目的字符集 5.创建SpringBoot工程

01、python实现matlab的插值算法,以及验证

import numpy as np from scipy.interpolate import griddata import sys def griddata_wrapper(x, y, v, xq, yq, method): """ 包装scipy的griddata函数,支持单个点或多个点的插值 """ try: # 将输入转换为numpy数组…

React ahooks——useRequest

目录 简介 1. 核心功能 2. 基本用法 3. 高级用法 &#xff08;1&#xff09;轮询请求&#xff08;Polling&#xff09; &#xff08;2&#xff09;防抖&#xff08;Debounce&#xff09; &#xff08;3&#xff09;依赖刷新&#xff08;refreshDeps&#xff09; &#x…

re正则、Xpath、BeautifulSouplxml 区别

目录 1. re 正则表达式2. XPath3. BeautifulSoup + lxml4. 功能特性对比5.对比与建议在网页数据解析中,正则表达式(re)XPath(常结合lxml)BeautifulSoup(常依赖解析器如lxml)是三种主流技术,各有核心差异和适用场景。 1. re 正则表达式 优势:文本匹配效率高,尤其适用于…

教师办工专用 资源包|课件+手抄报+PPT模板+常用表格 PDF格式93GB

如果家里亲戚或朋友有走上教育之路的人&#xff0c;给他这份整合可以减轻不少工作负担&#xff0c;更快地适应教育的节奏。也可以发给孩子的老师让他在平时做个班级活动的参考 《老师教学办工资源包》包括手抄报大全、教学计划、工作总结、培训手册、课程表等教学、办公常用资…

算法第37天| 完全背包\518. 零钱兑换 II\377. 组合总和 Ⅳ\57. 爬楼梯

完全背包 完全背包和01背包的区别 纯完全背包&#xff0c;遍历背包和物品的顺序是可以对调的&#xff0c;只要求得出最大价值&#xff0c;不要求凑成总和的元素的顺序&#xff1b; 01背包&#xff0c;遍历背包和物品的顺序是不可以对调的&#xff08;一维不行&#xff0c;二维…

七彩喜智慧康养平台:重构银发生活的数字守护网

随着社会老龄化程度的不断加深&#xff0c;如何让老年人安享幸福晚年成为社会关注的焦点。 在这一背景下&#xff0c;七彩喜智慧康养平台应运而生&#xff0c;以创新的科技手段和贴心的服务理念&#xff0c;为老年人的生活带来了诸多好处&#xff0c;发挥着重要作用&#xff0…

【设计模式】用观察者模式对比事件订阅(相机举例)

&#x1f4f7; 用观察者模式对比事件订阅(相机举例) 标签&#xff1a;WPF、C#、Halcon、设计模式、观察者模式、事件机制 在日常开发中&#xff0c;我们经常使用 事件机制&#xff08;Event&#xff09; 来订阅图像采集信号。然而当系统日益复杂&#xff0c;多个模块同时需要响…

【数据分析九:Association Rule】关联分析

一、数据挖掘定义 数据挖掘&#xff1a; 从大量的数据中挖掘那些令人感兴趣的、有用的、隐含的、先前未知的 和可能有用的 模式或知识 &#xff0c;并据此更好的服务人们的生活。 二、四类任务 数据分析有哪些任务&#xff1f; 今天我们来讲述其中的关联分析 三、关联分析 典…

AWS Security Hub邮件告警设置

问题 需要给AWS Security Hub设置邮件告警。 前提 已经启用AWS Security Hub。 AWS SNS 创建一个AWS Security Hub告警主题SecurityHub-Topic&#xff0c;如下图&#xff1a; 创建完成后&#xff0c;订阅该主题。 AWS EventBridge 设置规则名SecurityHubFindings-Rules…