4

自适应且不可删除的水印蒙层 - 泼墨作山水

 1 year ago
source link: https://www.cnblogs.com/wwwxxxyyy/p/16963848.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

2134246-20221207171601945-469478473.png

canvas自适应文字长度,旋转角度生成水印背景图

2134246-20221207194901791-147391185.png
  • 设置canvas字体大小后,通过ctx.measureText(text).width获取两行文字的宽度text1,text2,取最大宽度为文本框宽度textWidth
  • 设置两行文字间距,可得文本框高度:textHeight=2*fontsize+ space_line
  • 计算最小一个能够完全包裹旋转后文本的盒子宽高
    已知旋转角度为rotate=>得到弧度rad = (rotate*Math.pi) /180
    单个水印图平铺成为蒙层的背景图,space_x,space_y用于调整水印之间的间距
    2134246-20221208135932996-1944789905.png


function drawWatermark(el, config = {}) { if (!el) return; // 默认配置 let { text1 = '今天也要保持愉悦鸭~', //文本1 text2 = '2022-12-07', // 文本2 space_x = 0, // x轴间距 space_y = 0, // y轴间距 space_line = 20, //两列文字的间距 font = 'Microsoft JhengHei bold', fontSize = 40, // 字体 color = 'rgba(22,22,22,1)', // 字色 rotate = 30 // 倾斜度 } = config; const canvas = document.createElement('canvas'); el.appendChild(canvas); const ctx = canvas .getContext('2d'); ctx.font = fontSize + 'px ' + font; //设置好fontsize才能正确计算出文本宽度 let tw1= ctx.measureText(text1).width; let tw2= ctx.measureText(text2).width; let textWidth = Math.max(tw1, tw2); //文本最长宽度为文本框宽度 let textHeight = fontSize * 2 + space_line; //文本框高度为两个文本+行间距 let rad = (rotate * Math.PI) / 180; //角度转弧度 let sin = Math.sin(rad ); let cos = Math.cos(rad ); let width = textWidth * cos + textHeight * sin + space_x ; //为包裹住文本框的最小盒子宽度 let height = textWidth * sin + textHeight * cos + space_y; //为包裹住文本框的最小盒子高度 canvas.width = width; canvas.height = height; canvas.style.cssText = `width:${width}px;height:${height}px;display:none;`; ctx.translate(space_x , textWidth * sin + space_y ); // 移动旋转中心 ctx.rotate((-1 * (rotate * Math.PI)) / 180); //旋转文本框 ctx.fillStyle = color; ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; ctx.font = fontSize + 'px ' + font; ctx.fillText(text1, (textWidth - tw1) / 2, 0.5 * fontSize); //文本在文本框中居中显示 ctx.fillText(text2, (textWidth - tw2) / 2, 1.5 * fontSize + space_line); //文本在文本框中居中显示 return canvas.toDataURL('image/png'); },

生成蒙层

在目标元素下添加一个相对定位的子元素,将水印图片平铺作为背景图。

禁止蒙层的删除和修改

  • 删除或移动element
  • 修改style

transform: translate(100%,100%);
display: none;
visibility: hidden;
取消背景图



function createMask(el) { //创建蒙层 let $mask = document.createElement('div'); //判断蒙层父元素是否有定位 let position = window.getComputedStyle(el, null).position; if (position === 'static') { el.style.position = 'relative'; } //设置蒙层样式 let style = `visibility: visible !important; transform: translate(0,0) !important; display: block !important; visibility: visible !important; width: 100% !important; height: 100% !important; pointer-events: none !important; background-color: rgba(0, 0, 0, 0)!important; background-repeat: repeat !important; position: absolute !important; top: 0px !important; left: 0px !important; z-index: 999 !important; background-image: url(${drawWatermark(el)}) !important`; $mask.setAttribute('style', style); //添加蒙层 el.append($mask); // 创建MutationObserver el.observer = new MutationObserver((mutationRecord) => { //处理DOM mutationRecord.forEach((mutation) => { // 蒙层删除或者被移动到别处 if (mutation.target === el && mutation.removedNodes[0] == $mask) { el.append($mask); } else if (mutation.target == $mask && mutation.attributeName === 'style') { // 蒙层被更改样式 在监听到蒙层样式更改后,赋值的新的样式会导致再次触发监听回调,所以需要在监听事件中判断何时需要赋值 const changestyle = $mask?.getAttribute('style'); if (changestyle !== style) { $mask.setAttribute('style', style); } } }); }); // 启动监控 el.observer.observe(el, { childList: true, attributes: true, subtree: true }); return $mask; },

行内样式加important是为了防止通过添加class或其他css覆盖样式(暂时没有找到怎么如何通过修改css的方式更改样式的监听方式)
踩得一个坑
设置元素的行内样式有很多种

let style = 'width:100%;height:100%' 适用单个样式更改
element.style.width =100% ;element.style['height'] =100%
element.style.cssText = style
element.setAttribute('style',style )

方式二设置样式后,行内样式格式和赋值时的style的格式不一样,获取到行内style后直接进行===判断,回造成死循环

解决方法:

  • 第一次监听到蒙层更改时,立刻移除蒙层,重新生成新蒙层
  • 写个函数判断不同格式的两个样式属性上是否相等

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK