大屏天气展示太普通?视觉升级!用 Canvas 做动态天气遮罩,雷阵雨效果直接封神

之前做天气那个模块的时候,突发奇想想做一个大屏实时展示天气状况的蒙版。# Vue实现大屏获取当前所处城市及当地天气(纯免费)

需求

现在大屏上展示天气一般都是在左上/右上 做天气的图标/纯文字的展示,虽然看起来非常直观,但是对于大屏这种需要炫酷效果的产品显得不合适。

目前市面上对于天气这一块也并不是非常重视,我接触的大屏项目/产品对这部分基本都没啥要求。

但是能够展示天气效果对于大屏本身有相当不错的加成效果。

所以我开发了这个大屏天气展示蒙版组件,能够根据当前天气状况以蒙版的形式展示出来,目前支持多种天气的展示效果。

方案

视频方案

一开始考虑的是纯视频解决方案,首先说这个方案非常的简单,将视频以背景图的形式放在蒙版上,通过 pointer-events: none; 鼠标穿透就能算是完成了。

但是实际操作过程中发现问题比较多,首先是透明背景需要特定格式的视频才能够支持。

必须使用支持 Alpha 通道(透明通道)的视频格式‌。

常见支持透明背景的格式包括:

  • ‌WebM(VP8 或 VP9 编码 + Alpha 通道)‌:Chrome、Firefox 和 WebView2 等 Chromium 内核环境支持良好 。
  • ‌MOV(Apple ProRes 4444 编码)‌:支持 Alpha 通道,但主要在 macOS 和专业软件(如 Final Cut Pro、After Effects)中使用 ‌。
  • ‌MP4(H.265/HEVC 编码)‌:部分平台(如 WebView2)支持含 Alpha 通道的 H.265 视频。

但是我在网上并没有找到相应格式的视频,自己录也弄得不好,所以放弃了。

另外以视频作为背景图在弱网环境下比较难加载,毕竟视频一般都要超过5M以上了。

但是如果有相应的视频,效果做出来绝对是最顶尖的。

GIF动图方案

和视频方案基本一致,唯一的区别是使用 GIF 动图作为背景图使用,效果也非常好。

问题点在于需要UI做一系列的动图效果,GIF 动图在加载上速度也不算太快,毕竟比较好的动图也不会太小。

还有一个问题在于如果屏幕大小发生变化,或者不是标准屏,可能存在图片拉伸/裁切等问题。

如果有UI协助,采用这个方案也非常不错。

Canvas渲染

采用 Canvas 渲染的方案实现这个是我最后的选择,原因有三:

  • Canvas性能开销不算太大,对低端设备相对比较友好
  • Canvas不依赖静态资源,弱网环境下不影响加载效果
  • Canvas能够根据屏幕大小达到自适应效果,避免特殊屏幕尺寸显示异常

采用 Canvas 粒子效果和渐变效果模拟阳光和雨滴、雪花等等状态,实现天气状态。

代码

初始化遮罩层

目前使用的是 Vue3 框架,因为是遮罩层所以采用 pointer-events: none; 鼠标穿透,避免影响大屏正常的操作。

html 复制代码
<template>
    <canvas
        ref="weatherCanvas"
        class="weather-mask"
        :style="{ opacity: maskOpacity }"
    ></canvas>
</template>

<style scoped>
.weather-mask {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none; /* 鼠标事件穿透 */
    z-index: 10; /* 确保在内容上方,可根据项目调整 */
}
</style>

这里需要注意,初始化画布的时候要记得设置一下width、height,让画布充满整个屏幕。

晴天效果

晴天效果采用光照渐变效果,在 Canvas 中绘制了一个从左上角到右下角线性渐变的效果,来模拟阳光照射的感觉。

同时增加部分光斑效果,模仿阳光投射在玻璃上的感觉。

js 复制代码
// 创建从左上角到右下角的线性渐变(模拟阳光照射)
lightGradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);

// 绘制光斑效果
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = `rgba(255, 255, 200, ${Math.random() * 0.1 + 0.05})`;
ctx.fill();

雨天效果

雨天采用粒子效果,实现细长的雨丝效果,这里没有做明显的区分,对于小雨、中雨、大雨。

其实想要区分也很简单,只要控制粒子的数量和速度即可。

js 复制代码
ctx.beginPath();
ctx.moveTo(particle.x, particle.y);
ctx.lineTo(particle.x, particle.y + particle.height);
ctx.strokeStyle = particle.color.replace('OPACITY', particle.opacity);
ctx.lineWidth = particle.width;
ctx.stroke();

这里我进行了简单的封装,因为雨天、雪天、雾天等等大部分都用到了粒子效果,所以针对粒子的绘制部分进行了封装。

因为下雨是一个连续的绘制过程,所以动画部分做了简单的循环。

js 复制代码
const animate = () => {
    updateParticles(props.weatherType);
    animationId = requestAnimationFrame(animate);
};

下雪效果

下雪本质上和下雨区别不大,唯一的区别是粒子的状态、运动速度和运动方向。

这里没有采用雪花造型的粒子,确实做出来了,但是效果并不好,不如这种圆形的效果看起来好一些。

雪花的绘制和雨滴的绘制区别在于,雨滴的宽度是1,而雪花的大小是一定范围内随机的。

js 复制代码
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
ctx.fillStyle = particle.color.replace('OPACITY', particle.opacity);
ctx.fill();

雷阵雨效果

雷阵雨效果是这里面个人觉得做的最好的一个,通过对下雨效果增加随机雷电闪烁屏幕的效果,达到雷阵雨天气的遮罩。

下雨仍然是复用的。

js 复制代码
// 绘制主闪电路径
ctx.globalCompositeOperation = 'lighter';
ctx.strokeStyle = `rgba(255, 255, 255, ${thunderAlpha})`;
ctx.lineWidth = Math.random() * 8 + 4;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(startX, startY);

// 绘制闪电分支
ctx.lineWidth = Math.random() * 4 + 1;
ctx.beginPath();
ctx.moveTo(branch.startX, branch.startY);
let bx = branch.startX;
let by = branch.startY;
const dx = Math.random() * 30 - 15;
const dy = Math.random() * 20 + 5;
ctx.lineTo(bx + dx, by + dy);
bx += dx;
by += dy;
ctx.stroke();

// 闪烁效果
ctx.fillStyle = `rgba(255, 255, 255, ${thunderAlpha * 0.1})`;

总结

这个遮罩我做了好几天,Canvas部分我也不是特别的熟悉,所以很多地方仍然有非常大的优化空间,有感兴趣的朋友可以移步下面的文章获取源代码。

# 动态天气实时渲染动态生成组件,附源代码及详细注释

至于为啥收费,我也是想尝试一下代码还能不能搞到钱,毕竟现在的软件行业白嫖是大家的常态。

如果您能支持1元钱那我不胜感激,如果确实认为不值,自己能够写出更好的,那我也祝福。

一共做个几个效果:晴、雨、雪、雾、雷阵雨、多云、沙尘、阴天。有兴趣的朋友可以运行起来自行查看一下。

相关推荐
Lee川2 小时前
现代Web开发中的CSS继承、Flexbox布局与LocalStorage交互:从文档解析到实践应用
前端·css
炫饭第一名2 小时前
速通Canvas指北🦮——图形、文本与样式篇
前端·javascript·程序员
本末倒置1832 小时前
面向 Vue 开发者的 Next.js 快速入门指南
前端·vue.js
暴走的小呆2 小时前
vue3暗影代理:非原始值的响应式迷局
前端
1024小神2 小时前
bun+hono实现websocket长链接通许的demo
前端
滕青山2 小时前
文本字符数统计 在线工具核心JS实现
前端·javascript·vue.js
十二7402 小时前
前端缓存踩坑实录:从版本号管理到自动化构建
前端·javascript·nginx
over6972 小时前
从 URL 输入到页面展示:一次完整的 Web 导航之旅
前端·面试·架构
Giant1002 小时前
TypeScript 核心知识点(覆盖 90% 开发场景)
前端