@jkun/watermark
Version:
Stencil Component Starter
394 lines (393 loc) • 11.8 kB
JavaScript
import { Host, h, writeTask } from '@stencil/core';
import { rotateWatermark, getPixelRatio } from '../../utils/utils';
export class IvyWatermark {
constructor() {
this.BaseSize = 2;
this.FontGap = 3;
this.getMarkSize = (ctx) => {
let defaultWidth = 120;
let defaultHeight = 64;
if (!this.image && ctx.measureText) {
ctx.font = `${parseFloat(this.fontSize)}px ${this.fontFamily}`;
const contents = [this.content];
const widths = contents.map(item => ctx.measureText(item).width);
defaultWidth = Math.ceil(Math.max(...widths));
defaultHeight = parseFloat(this.fontSize) * contents.length + (contents.length - 1) * this.FontGap;
}
return [this.width ? parseFloat(this.width) : defaultWidth, this.height ? parseFloat(this.height) : defaultHeight];
};
this.fillTexts = (ctx, drawX, drawY, drawWidth, drawHeight) => {
const ratio = getPixelRatio();
const mergedFontSize = parseFloat(this.fontSize) * ratio;
ctx.font = `${this.fontStyle} normal ${this.fontWeight} ${mergedFontSize}px/${drawHeight}px ${this.fontFamily}`;
ctx.fillStyle = this.fontColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.translate(drawWidth / 2, 0);
const contents = [this.content];
contents === null || contents === void 0 ? void 0 : contents.forEach((item, index) => {
const y = drawY + index * (mergedFontSize + this.FontGap * ratio);
ctx.fillText(item !== null && item !== void 0 ? item : '', drawX, y);
});
};
this.appendWatermark = (base64Url, markWidth) => {
if (this.watermarkRef) {
this.waterSrc = base64Url;
this.backgroundSize = `${(parseFloat(this.gapX) + markWidth) * this.BaseSize}px`;
}
};
this.renderWatermark = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (ctx) {
const ratio = getPixelRatio();
const [markWidth, markHeight] = this.getMarkSize(ctx);
const canvasWidth = (parseFloat(this.gapX) + markWidth) * ratio;
const canvasHeight = (parseFloat(this.gapY) + markHeight) * ratio;
canvas.setAttribute('width', `${canvasWidth * this.BaseSize}px`);
canvas.setAttribute('height', `${canvasHeight * this.BaseSize}px`);
const drawX = (parseFloat(this.gapX) * ratio) / 2;
const drawY = (parseFloat(this.gapY) * ratio) / 2;
const drawWidth = markWidth * ratio;
const drawHeight = markHeight * ratio;
const rotateX = (drawWidth + parseFloat(this.gapX) * ratio) / 2;
const rotateY = (drawHeight + parseFloat(this.gapY) * ratio) / 2;
const alternateDrawX = drawX + canvasWidth;
const alternateDrawY = drawY + canvasHeight;
const alternateRotateX = rotateX + canvasWidth;
const alternateRotateY = rotateY + canvasHeight;
ctx.save();
rotateWatermark(ctx, rotateX, rotateY, parseFloat(this.rotate));
if (this.image) {
const img = new Image();
img.onload = () => {
ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight);
ctx.restore();
rotateWatermark(ctx, alternateRotateX, alternateRotateY, parseFloat(this.rotate));
ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
this.appendWatermark(canvas.toDataURL('image/png'), markWidth);
};
img.crossOrigin = 'anonymous';
img.referrerPolicy = 'no-referrer';
img.src = this.image;
}
else {
this.fillTexts(ctx, drawX, drawY, drawWidth, drawHeight);
ctx.restore();
rotateWatermark(ctx, alternateRotateX, alternateRotateY, parseFloat(this.rotate));
this.fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight);
this.appendWatermark(canvas.toDataURL('image/png'), markWidth);
}
}
};
this.image = null;
this.waterSrc = '';
this.backgroundSize = null;
this.width = undefined;
this.height = undefined;
this.content = '';
this.rotate = '-22';
this.zIndex = '1000';
this.fontSize = '16px';
this.fontWeight = 'normal';
this.fontStyle = 'normal';
this.fontColor = 'rgba(0,0,0,0.15)';
this.fontFamily = 'PingFang SC, sans-serif';
this.gapX = '100';
this.gapY = '100';
this.offsetY = '0';
this.offsetX = '0';
this.watermarkIndex = '1000';
}
watchZIndexHandler(val) {
this.watermarkIndex = parseInt(val).toFixed(0);
}
render() {
return (h(Host, null, h("div", { class: "watermark", ref: el => (this.watermarkRef = el), tabindex: "-1", style: { zIndex: this.watermarkIndex, backgroundImage: `url(${this.waterSrc})`, backgroundSize: this.backgroundSize } }), h("slot", null)));
}
componentDidLoad() {
writeTask(() => {
this.renderWatermark();
});
}
static get is() { return "ivy-watermark"; }
static get encapsulation() { return "shadow"; }
static get originalStyleUrls() {
return {
"$": ["ivy-watermark.css"]
};
}
static get styleUrls() {
return {
"$": ["ivy-watermark.css"]
};
}
static get properties() {
return {
"width": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "width",
"reflect": false
},
"height": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "height",
"reflect": false
},
"content": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "content",
"reflect": false,
"defaultValue": "''"
},
"rotate": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "rotate",
"reflect": false,
"defaultValue": "'-22'"
},
"zIndex": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "z-index",
"reflect": false,
"defaultValue": "'1000'"
},
"fontSize": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "font-size",
"reflect": false,
"defaultValue": "'16px'"
},
"fontWeight": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "font-weight",
"reflect": false,
"defaultValue": "'normal'"
},
"fontStyle": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "font-style",
"reflect": false,
"defaultValue": "'normal'"
},
"fontColor": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "font-color",
"reflect": false,
"defaultValue": "'rgba(0,0,0,0.15)'"
},
"fontFamily": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "font-family",
"reflect": false,
"defaultValue": "'PingFang SC, sans-serif'"
},
"gapX": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "gap-x",
"reflect": false,
"defaultValue": "'100'"
},
"gapY": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "gap-y",
"reflect": false,
"defaultValue": "'100'"
},
"offsetY": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "offset-y",
"reflect": false,
"defaultValue": "'0'"
},
"offsetX": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "offset-x",
"reflect": false,
"defaultValue": "'0'"
}
};
}
static get states() {
return {
"image": {},
"waterSrc": {},
"backgroundSize": {},
"watermarkIndex": {}
};
}
static get watchers() {
return [{
"propName": "zIndex",
"methodName": "watchZIndexHandler"
}];
}
}