参考:
- html、js、canvas实现水印_html页面使用canvas绘制重复水印-CSDN博客
效果
不求水印显示完全。
实现代码
<template>
<div class="watermark" ref="waterMark"></div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch, Ref } from 'vue-property-decorator'
@Component({
name: 'WaterMark',
components: {},
})
export default class WaterMark extends Vue {
@Prop({ default: '' })
private text!: string // 水印文本内容
// 水印配置参数
private config: any = {
angle: -30, // 统一倾斜角度 [-90, 90]
fontSize: 20, // 字体大小
fontFamily: 'Arial, sans-serif', // 字体
color: 'rgba(0, 0, 0, 0.5)', // '#cccccc', // 文字颜色
opacity: 0.5, // 透明度
zIndex: 999, // 层叠顺序
gap: [200, 200], // 水印之间的间距[行,纵]
}
@Ref()
private waterMark!: HTMLDivElement
@Watch('text', { immediate: true })
private onTextChange() {
this.createWatermarks()
}
// 批量创建水印
private createWatermarks() {
this.addWatermark(this.text)
}
mounted() {
// 确保页面加载完成后再创建水印
this.$nextTick(() => {
this.createWatermarks()
})
// 窗口变化时重新生成
window.addEventListener('resize', this.createWatermarks)
}
private addWatermark(text: any) {
if (!this.waterMark && !text) {
return
}
const { fontSize, opacity, color, fontFamily, angle, gap } = this.config
const canvas: any = document.createElement('canvas')
const ctx: any = canvas.getContext('2d')
const width: any = window.innerWidth
const height: any = window.innerHeight
let nWidth = width
let nHeight = height
if (angle) {
// 根据角度计算宽高和原点移动
const radian = (angle * Math.PI) / 180
const sin = Math.sin(Math.abs(radian))
const cos = Math.cos(Math.abs(radian))
nWidth = width + height * sin
nHeight = width * sin + height * cos
canvas.width = nWidth
canvas.height = nHeight
ctx.translate(-height * sin * cos, height * sin * sin)
ctx.rotate(radian)
}
ctx.globalAlpha = opacity
ctx.font = `${fontSize}px ${fontFamily}`
ctx.fillStyle = color // 文字颜色和透明度
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
// 在页面上重复绘制水印
for (let x = 0, i = 0; x < nWidth; x += text.length * fontSize + gap[0]) {
for (let y = 0; y < nHeight; y += gap[1]) {
ctx.fillText(text, x + (i % 2) * (gap[0] / 2), y)
i++
}
}
const watermark = new Image()
watermark.src = canvas.toDataURL('image/png')
if (this.waterMark.style) {
this.waterMark.style.backgroundImage = `url(${watermark.src})`
this.waterMark.style.backgroundRepeat = 'repeat'
}
this.waterMark.dataset.watermark = 'true' // 标记水印元素
}
}
</script>
<style lang="scss" scoped>
.watermark {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 9999;
}
</style>
计算旋转后的宽高和移动原点位置
蓝色长方形为原画布长宽,已知为 h,w
(此处即为屏幕长宽)。
浅蓝色长方形为以A点为旋转中心,旋转x度之后的画布,
需要得到旋转之后能覆盖原画布大小的长宽-深蓝色长方形,即可求得:hsinX+w(长度没有很严格)
, hcosX+wsinX
旋转点也从 A点跑到了 B点:(- hsinXsinX, hsinXcosX)
。
公式补充
提示
如果要考虑文字都在可视区域,还需要考虑 textLeft
和 textRight
const measureText = ctx.measureText(text)
const textLeft = measureText.actualBoundingBoxLeft
const textRight = measureText.actualBoundingBoxRight
另外只要判断 x
和 y
值在合理区间之内即可。