Maison > interface Web > js tutoriel > Explication détaillée de la façon d'utiliser JS pour obtenir un effet de filigrane de superposition

Explication détaillée de la façon d'utiliser JS pour obtenir un effet de filigrane de superposition

藏色散人
Libérer: 2023-03-03 19:57:44
avant
2219 Les gens l'ont consulté

Le début du non-sens : implémentez simplement une petite fonction pour couvrir le filigrane. Le filigrane est généralement ajouté à l'image, puis charge directement l'image traitéeurl L'image n'est pas modifiée ici, mais le filigrane est ajouté directement. . Ajoutez un masque canvas sur le dom.

1. Effet

Avant le traitement

DIV

Explication détaillée de la façon dutiliser JS pour obtenir un effet de filigrane de superposition

IMG

Explication détaillée de la façon dutiliser JS pour obtenir un effet de filigrane de superposition

Après le traitement

DIV

Explication détaillée de la façon dutiliser JS pour obtenir un effet de filigrane de superposition

IMG

Explication détaillée de la façon dutiliser JS pour obtenir un effet de filigrane de superposition

Ajouter "un filigrane ici " (En fait, ce n'est pas un vrai filigrane) En atteignant DIV, l'événement clic sur le bouton ne sera pas cliquable à cause du masque

2. Code JS

class WaterMark{
    //水印文字
    waterTexts = []
    //需要添加水印的dom集合
    needAddWaterTextElementIds = null
    //保存添加水印的dom
    saveNeedAddWaterMarkElement = []
    //初始化
    constructor(waterTexts,needAddWaterTextElementIds){
        if(waterTexts && waterTexts.length != 0){
            this.waterTexts = waterTexts
        } else {
            this.waterTexts = ['水印文字哈哈哈哈','2022-12-08']
        }
        this.needAddWaterTextElementIds = needAddWaterTextElementIds
    }
    
    //开始添加水印
    startWaterMark(){
        const self = this
        if(this.needAddWaterTextElementIds){
            this.needAddWaterTextElementIds.forEach((id)=>{
                let el = document.getElementById(id)
                self.saveNeedAddWaterMarkElement.push(el)
            })
        } else {
            this.saveNeedAddWaterMarkElement = Array.from(document.getElementsByTagName('img'))
        }
        this.saveNeedAddWaterMarkElement.forEach((el)=>{
            self.startWaterMarkToElement(el)
        })
    }

    //添加水印到到dom对象
    startWaterMarkToElement(el){
        let nodeName = el.nodeName
        if(['IMG','img'].indexOf(nodeName) != -1){
            //图片,需要加载完成进行操作
            this.addWaterMarkToImg(el)
        } else {
            //普通,直接添加
            this.addWaterMarkToNormalEle(el)
        }
    }
        
    //给图片添加水印
    async addWaterMarkToImg(img){
        if(!img.complete){
            await new Promise((resolve)=>{
                img.onload = resolve
            })
        }
        this.addWaterMarkToNormalEle(img)
    }
    
    //给普通dom对象添加水印
    addWaterMarkToNormalEle(el){
        const self = this
        let canvas = document.createElement('canvas')
        canvas.width = el.width ? el.width : el.clientWidth
        canvas.height = el.height ? el.height : el.clientHeight
        let ctx = canvas.getContext('2d')
        let maxSize = Math.max(canvas.height, canvas.width)
        let font = (maxSize / 25)
        ctx.font = font + 'px "微软雅黑"'
        ctx.fillStyle = "rgba(195,195,195,1)"
        ctx.textAlign = "left"
        ctx.textBaseline = "top"
        ctx.save()
        let angle = -Math.PI / 10.0
        //进行平移,计算平移的参数
        let translateX = (canvas.height) * Math.tan(Math.abs(angle))
        let translateY = (canvas.width - translateX) * Math.tan(Math.abs(angle))
        ctx.translate(-translateX / 2.0, translateY / 2.0)
        ctx.rotate(angle)
        //起始坐标
        let x = 0
        let y = 0
        //一组文字之间间隔
        let sepY = (font / 2.0)
        while(y < canvas.height){
            //当前行的y值
            let rowCurrentMaxY = 0
            while(x < canvas.width){
                let totleMaxX = 0
                let currentY = 0
                //绘制水印
                this.waterTexts.forEach((text,index)=>{
                    currentY += (index * (sepY + font))
                    let rect = self.drawWater(ctx,text,x,y + currentY)
                    let currentMaxX = (rect.x + rect.width)
                    totleMaxX = (currentMaxX > totleMaxX) ? currentMaxX: totleMaxX
                    rowCurrentMaxY = currentY
                })
                x = totleMaxX + 20
            }
            //重置x,y值
            x = 0
            y += (rowCurrentMaxY + (sepY + font + (canvas.height / 5)))
        }
        ctx.restore()
        //添加canvas
        this.addCanvas(canvas,el)
    }

    //绘制水印
    drawWater(ctx,text,x,y){
        //绘制文字
        ctx.fillText(text,x,y)
        //计算尺度
        let textRect = ctx.measureText(text)
        let width = textRect.width
        let height = textRect.height
        return {x,y,width,height}
    }

    //添加canvas到当前标签的父标签上
    addCanvas(canvas,el){
        //创建div(canvas需要依赖一个div进行位置设置)
        let warterMarDiv = document.createElement(&#39;div&#39;)
        //关联水印dom对象
        el.warterMark = warterMarDiv
        //添加样式
        this.resetCanvasPosition(el)
        //添加水印
        warterMarDiv.appendChild(canvas)
        //添加到父标签
        el.parentElement.insertBefore(warterMarDiv,el)
    }

    //重新计算位置
    resetCanvasPosition(el){
        if(el.warterMark){
            //设置父标签的定位
            el.parentElement.style.cssText = `position: relative;`
            //设施水印载体的定位
            el.warterMark.style.cssText = &#39;position: absolute;top: 0px;left: 0px;pointer-events:none&#39;
        }
    }
}
Copier après la connexion

Usage

<div>
    <!-- 待加水印的IMG -->
    <img   style="max-width:90%" src="" alt="">
</div>

let waterMark = new WaterMark()
waterMark.startWaterMark();
Copier après la connexion

ctx. save() et ctx.restore() ne sont en fait pas très utiles ici, mais ils sont quand même ajoutés. Le but est de sauvegarder le contexte avant d'ajouter le filigrane et de restaurer le contexte avant le filigrane après avoir terminé le dessin. , ces mots en italique sont uniquement dans Cela prend effet entre ces deux lignes de code. Si vous dessinez d'autres lignes ci-dessous, cela ne sera pas affecté.

Pour empêcher le filigrane du masque de bloquer les boutons sous-jacents ou d'autres événements, vous devez ajouter l'attribut pointer-events:none à l'étiquette du masque.

Vous devez ajouter une balise parent en plus de l'étiquette pour ajouter le filigrane. La fonction de cette balise parent est d'ajouter des contraintes à la position du canevas de masque Ici, je souhaite utiliser MutationObserver. pour observer les changements dans body pour mettre à jour mask version canvas, cette tentative a échoué car des changements de mise en page complexes seront déclenchés dans ce rappel. Par conséquent, vous devez ajouter une balise parent directement à l'extérieur de l'étiquette où le filigrane est ajouté, et utiliser cette balise parent pour contraindre automatiquement la position du toile de masque.

MutationObserver La logique est la suivante Vous pouvez modifier la mise en page ou d'autres opérations dans le temps dans le rappel d'écoute (abandonner temporairement).

var MutationObserver = window.MutationObserver || window.webkitMutationObserver || window.MozMutationObserver;
var mutationObserver = new MutationObserver(function (mutations) {
    //修改水印位置
})

mutationObserver.observe(document.getElementsByTagName(&#39;body&#39;)[0], {
    childList: true, // 子节点的变动(新增、删除或者更改)
    attributes: true, // 属性的变动
    characterData: true, // 节点内容或节点文本的变动
    subtree: true // 是否将观察器应用于该节点的所有后代节点
})
Copier après la connexion

La taille de l'image ne peut être déterminée qu'une fois le chargement terminé, donc pour le fonctionnement de IMG, vous devez observer son événement complete.

3. Résumé et réflexions

Utilisez canvas ctx.drawImage(img, 0, 0) pour dessiner, puis chargez l'url générée par canvas.toDataURL('image/png') dans le précédent Sur l'image, c'est aussi un moyen. Cependant, parfois à cause de l'image, les données base64 de l'image composite finale sont donc vides, l'ajout direct d'un masque sert uniquement à l'affichage lui-même, pas à générer un véritable. Images composites. Un simple pseudo-filigrane a été implémenté. Il n'y a pas de code particulièrement compliqué. Le code est maladroit. [tenir les poings][tenir les poings]

Apprentissage recommandé : "Tutoriel vidéo JavaScript. "

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal