canvas水印生成

canvas水印生成

在大多数内部项目中,水印是一个常见需求。过去,当新项目需要添加水印时,通常是从旧项目中复制水印代码。这种做法不仅带来了大量重复工作,还导致了可维护性差的问题。另外,当前的方法在手动调整水印位置时,常常无法根据内容自动对齐。

本文旨在根据产品侧的规范设计方法,解决现有方法中的问题:

  • 统一格式,遵循需求文档
  • 自动居中对齐
  • 参数可配置,例如间距、旋转角度、透明度

以下是改进后的水印代码:

typescript 复制代码
import dayjs from 'dayjs'

class WatermarkManager {
  private watermarkId = 'custom-watermark-canvas'

  // 创建水印
  private createWatermark(username: string, angle: number, xGap: number, yGap: number): void {
    // 创建 canvas 元素
    const canvas = document.createElement('canvas')
    canvas.id = this.watermarkId
    canvas.width = window.innerWidth
    canvas.height = window.innerHeight
    canvas.style.position = 'fixed'
    canvas.style.top = '0'
    canvas.style.left = '0'
    canvas.style.zIndex = '1000'
    canvas.style.pointerEvents = 'none'
    canvas.style.opacity = '0.5'

    const ctx = canvas.getContext('2d')
    if (ctx) {
      ctx.clearRect(0, 0, canvas.width, canvas.height)

      ctx.font = '18px Arial'
      const firstContent = `xxxxx平台 ${username} ${dayjs().format('YYYY/MM/DD')}`
      const secondContent = '未经允许,不得外泄'
      const textWidth = ctx.measureText(firstContent).width
      const textHeight = 18

      ctx.font = '16px Arial'
      const subTextWidth = ctx.measureText(secondContent).width
      const subTextHeight = 16

      const totalHeight = textHeight + subTextHeight + 10 // 两行文字的总高度
      const maxWidth = Math.max(textWidth, subTextWidth) // 两行文字的最大宽度

      for (let x = 0; x < canvas.width; x += xGap) {
        for (let y = 0; y < canvas.height; y += yGap) {
          ctx.save()
          ctx.translate(x + maxWidth / 2, y + totalHeight / 2)
          ctx.rotate(angle * Math.PI / 180)

          // 绘制第一行文字
          ctx.font = '18px Arial'
          ctx.fillStyle = 'rgba(0, 0, 0, 0.15)'
          ctx.fillText(firstContent, -textWidth / 2, 0)

          // 绘制第二行文字
          ctx.font = '16px Arial'
          ctx.fillStyle = 'rgba(0, 0, 0, 0.15)'
          ctx.fillText(secondContent, -subTextWidth / 2, textHeight + 10)

          ctx.restore()
        }
      }
    }

    // 添加 canvas 到页面
    document.body.appendChild(canvas)
  }

  // 移除水印
  private removeWatermark(): void {
    const canvas = document.getElementById(this.watermarkId)
    if (canvas)
      canvas.remove()
  }

  // 设置水印
  public setWatermark(username: string, angle: number = -30, xGap: number = 200, yGap: number = 100): void {
    this.removeWatermark()
    this.createWatermark(username, angle, xGap, yGap)
  }

  // 清理水印
  public clearWatermark(): void {
    this.removeWatermark()
  }
}

const watermarkManager = new WatermarkManager()

export default watermarkManager

使用示例

js 复制代码
const watermarkManager = new WatermarkManager()

// 设置水印
watermarkManager.setWatermark('用户名', -30, 280, 280)

// 清空水印
watermarkManager.clearWatermark()

通过以上改进,实现水印的统一格式,自动对齐以及参数配置,避免了重复工作并提升了代码的可维护性。

相关推荐
你也向往长安城吗6 分钟前
推荐一个三维导航库:three-pathfinding-3d
javascript·算法
karrigan16 分钟前
async/await 的优雅外衣下:Generator 的核心原理与 JavaScript 执行引擎的精细管理
javascript
wycode24 分钟前
Vue2实践(3)之用component做一个动态表单(二)
前端·javascript·vue.js
wycode1 小时前
Vue2实践(2)之用component做一个动态表单(一)
前端·javascript·vue.js
第七种黄昏1 小时前
Vue3 中的 ref、模板引用和 defineExpose 详解
前端·javascript·vue.js
我是哈哈hh2 小时前
【Node.js】ECMAScript标准 以及 npm安装
开发语言·前端·javascript·node.js
张元清2 小时前
电商 Feeds 流缓存策略:Temu vs 拼多多的技术选择
前端·javascript·面试
pepedd8643 小时前
浅谈js拷贝问题-解决拷贝数据难题
前端·javascript·trae
@大迁世界3 小时前
useCallback 的陷阱:当 React Hooks 反而拖了后腿
前端·javascript·react.js·前端框架·ecmascript
小高0073 小时前
📌React 路由超详解(2025 版):从 0 到 1 再到 100,一篇彻底吃透
前端·javascript·react.js