Skip to content

Instantly share code, notes, and snippets.

@iamspark1e
Created May 14, 2024 08:38
Show Gist options
  • Save iamspark1e/9380c03960e1962b3e9368e6c1bbb9e5 to your computer and use it in GitHub Desktop.
Save iamspark1e/9380c03960e1962b3e9368e6c1bbb9e5 to your computer and use it in GitHub Desktop.
type WatermarkCanvasConfigurableOptions = {
textAlign?: string,
textBaseline?: string,
font?: string,
fillStyle?: string,
}
type WatermarkConfiguration = {
container: HTMLElement | null,
id: string,
width: number,
height: number,
content: string,
rotate: number,
canvasProps?: WatermarkCanvasConfigurableOptions,
enableGuard?: boolean
}
// TODO:
// 1. create watermark dom
// 2. mount watermark to `options.container`
// 3. set up guard `MutationObserver` if configured
function createWatermarkDom(config: WatermarkConfiguration) {
const canvas = document.createElement("canvas");
canvas.setAttribute("width", config.width + "px");
canvas.setAttribute("height", config.height + "px");
const ctx = canvas.getContext("2d");
if (ctx) {
if (config.canvasProps) {
// @ts-ignore
for (let i of config.canvasProps) { ctx[i] = config.canvasProps[i]; }
}
ctx.rotate((Math.PI / 180) * config.rotate);
ctx.fillText(config.content, config.width / 2, config.height / 2);
}
const base64Url = canvas.toDataURL();
let div = document.createElement('div')
div.setAttribute('style', `
background-image: url(${base64Url});
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
z-index: 9999;
background-repeat: repeat;
`)
div.id = config.id;
return div;
}
function mountWatermark(config: WatermarkConfiguration, watermark: HTMLElement) {
if (!config.container) {
console.log("mount container not found, skipped.");
return;
}
let current = watermark.cloneNode();
config.container.append(current);
if (config.enableGuard) {
if (!window.MutationObserver) {
console.log("watermark guard relays on `MutationObserver` but current environment not support this feature");
return;
}
let selfObserver = generateMutationObserver((mutations: MutationRecord[], ob: MutationObserver) => {
// 自身有任何变化都触发销毁 => 重新生成 => 重新生成并开始Observer
ob.disconnect();
if (config.container) {
let current = watermark.cloneNode();
config.container.append(current);
selfObserver.observe(current, {
attributes: true,
childList: true,
characterData: true,
subtree: true,
})
} else {
console.log("mount container not found, skipped.")
}
})
selfObserver.observe(current, {
attributes: true,
childList: true,
characterData: true,
subtree: true,
})
}
}
function generateMutationObserver(observerCallback: Function) {
let mo = new MutationObserver((mutations) => {
observerCallback(mutations, mo);
});
return mo;
}
function postMountWatermark(config: WatermarkConfiguration, watermark: HTMLElement) {
if (!config.container) {
console.log("mount container not found, skipped.");
return;
}
// 容器监听,当水印元素被移除时,重新初始化水印元素
let containerObserver = generateMutationObserver((mutations: MutationRecord[], ob: MutationObserver) => {
mutations.forEach((mu: MutationRecord) => {
if (mu.type === 'childList' && mu.removedNodes.length > 0) {
let watermarkNodeRemoved = false;
for (const n of mu.removedNodes) {
if (n instanceof HTMLElement && n.id === config.id) {
watermarkNodeRemoved = true;
}
}
if (watermarkNodeRemoved) {
mountWatermark(config, watermark);
}
}
})
})
containerObserver.observe(config.container, {
childList: true,
subtree: true
})
}
export default function(config: WatermarkConfiguration) {
let watermark = createWatermarkDom(config)
mountWatermark(config, watermark);
postMountWatermark(config, watermark);
}
// example
const config: WatermarkConfiguration = {
container: document.getElementById("1234"),
id: "dddd",
width: 200,
height: 200,
content: "11111111111",
rotate: 330,
enableGuard: true,
canvasProps: {
textAlign: "center",
textBaseline: "middle",
font: "13px system-ui",
fillStyle: "rgba(0,0,0,0.1)"
}
}
// initWatermark(config)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment