UNPKG

@inweb/markup

Version:
188 lines (150 loc) 6.05 kB
import Konva from "konva"; import { IMarkupImage, IMarkupImageParams } from "../IMarkupImage"; export class KonvaImage implements IMarkupImage { private _ref: Konva.Image; private _canvasImage: HTMLImageElement; private _ratio = 1; private readonly EPSILON = 10e-6; private readonly BASE64_HEADER_START = "data:image/"; private readonly BASE64_NOT_FOUND = "data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAADsAAAA7AF5KHG9AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAmhJREFUWIXtlr9rVEEQxz+H8RQUJIdeIopYm0vkCg0GBBtbG1NF7Kxt7dR/IGIw/uhTaBNLERURg2kCEUyCYCPi70b0InjGS57FzOZN3r19d+9HJIVfWO52dma/s7Mz8xa2KAaBCWAR+AkECWOmSOIdwC1gtQOpHc+NfQ8wClQ8+1d0vcdH/lQ3bSIRGAZ2pTjAqNovANXIWlXlAXA2zvi2Ln4AjqYgtagYEutENSLvjRoOImFv5iB32Ae8UrLXwFBk3h9ndF0VJnKSO9gTu3yKu5Z1LKnS8YIcABgw5Ks692JZFXcXRJ46Aq6kikCnHNi/mQ50WwVtfaIoBzL3gRk2drSscJ2wrc4VvUoe2wn/41/iBfoVLRnBGnDSY3AAKacy8AmYR+o7K1zCl6wgrgpOAc/MuhvfgMuk+1JGHQgSBcAloKXy78AjYBppJk5/noTulseBMZ23iD/piHFkEdgTQzKk+5wHjmHC3cmBg0BD5xcSTrFXyQPgIWFtDwMvab+2N8DpbhyY1v/3E8gdDgNfVX9SCVZ0/gW4B0wB71S2BpxLcuCM/jaQSHSDEeAX4VMuAG4gTzyHbcAVXXO6GxxwIX+vvxe7JHcYQ07nHqklj96UIW/YhSWzMKcep8VVtf8B1Dw6h4DfhB+sdbgn2R+gnoEc5NR3dZ+3QJ9H74HqXLPCGlJyTfI9y3YCs0owq3OLOpKkLeBI1HhSDT/mdKIPiUCARMTlQx34TMLjtww8IczmO8AJ/N/2JNSQXAiQ671JePePge0+wzJSQq4FFzlaenIvucUAkiQLhC/mLGNZ9xgn5s63BP4CCk0QDtm4BhoAAAAASUVORK5CYII="; constructor(params: IMarkupImageParams, ref = null) { if (ref) { if (!ref.src || !ref.src.startsWith(this.BASE64_HEADER_START)) ref.src = this.BASE64_NOT_FOUND; if (ref.height() <= this.EPSILON) ref.height(32); if (ref.width() <= this.EPSILON) ref.width(32); this._ref = ref; this._canvasImage = ref.image(); this._ratio = this._ref.height() <= this.EPSILON || this._ref.width() <= this.EPSILON ? 1 : this._ref.height() / this._ref.width(); return; } if (!params) params = {}; if (!params.position) params.position = { x: 0, y: 0 }; if (!params.src || !params.src.startsWith(this.BASE64_HEADER_START)) params.src = this.BASE64_NOT_FOUND; this._canvasImage = new Image(); this._canvasImage.onload = () => { this._ref.image(this._canvasImage); if (this._ref.height() <= this.EPSILON) this._ref.height(this._canvasImage.height); if (this._ref.width() <= this.EPSILON) this._ref.width(this._canvasImage.width); this._ratio = this._ref.height() <= this.EPSILON || this._ref.width() <= this.EPSILON ? 1 : this._ref.height() / this._ref.width(); // need to rescale only if input width and height are 0 - we do not loading Viewpoint with existing params if ( (params.width <= this.EPSILON || params.height <= this.EPSILON) && (params.maxWidth >= this.EPSILON || params.maxWidth >= this.EPSILON) ) { const heightOutOfCanvas = params.maxHeight - this._canvasImage.height; const widthOutOfCanvas = params.maxWidth - this._canvasImage.width; if (heightOutOfCanvas <= this.EPSILON || widthOutOfCanvas <= this.EPSILON) { if (widthOutOfCanvas <= this.EPSILON && widthOutOfCanvas < heightOutOfCanvas / this._ratio) { this._ref.height(params.maxWidth * this._ratio); this._ref.width(params.maxWidth); } else { this._ref.width(params.maxHeight / this._ratio); this._ref.height(params.maxHeight); } } } }; this._canvasImage.onerror = () => { this._canvasImage.onerror = function () {}; this._canvasImage.src = this.BASE64_NOT_FOUND; }; this._canvasImage.src = params.src; this._ref = new Konva.Image({ x: params.position.x, y: params.position.y, image: this._canvasImage, width: params.width ?? 0, height: params.height ?? 0, draggable: true, }); this._ref.on("transform", (e) => { const attrs = e.target.attrs; if (attrs.rotation !== this._ref.rotation()) this._ref.rotation(attrs.rotation); const scaleByX = Math.abs(attrs.scaleX - 1) > 10e-6; const scaleByY = Math.abs(attrs.scaleY - 1) > 10e-6; let newWidth = this._ref.width(); if (scaleByX) newWidth *= attrs.scaleX; let newHeight = this._ref.height(); if (scaleByY) newHeight *= attrs.scaleY; if (e.evt.ctrlKey || e.evt.shiftKey) { if (scaleByX) { this._ref.width(newWidth); this._ref.height(newWidth * this._ratio); } else { this._ref.width(newHeight / this._ratio); this._ref.height(newHeight); } } else { if (scaleByX) { this._ref.width(newWidth); } if (scaleByY) { this._ref.height(newHeight); } } this._ref.scale({ x: 1, y: 1 }); }); this._ref.id(this._ref._id.toString()); } getSrc(): string { return this._canvasImage.src; } setSrc(src: any) { this._canvasImage.src = src; } getWidth(): number { return this._ref.width(); } setWidth(w: number): void { this._ref.width(w); this._ref.height(w * this._ratio); } getHeight(): number { return this._ref.height(); } setHeight(h: number): void { this._ref.height(h); this._ref.width(h / this._ratio); } ref() { return this._ref; } id(): string { return this._ref.id(); } enableMouseEditing(value: boolean): void { this._ref.draggable(value); } type(): string { return "Image"; } getRotation(): number { return this._ref.rotation(); } setRotation(degrees: number): void { this._ref.rotation(degrees); } getZIndex(): number { return this._ref.zIndex(); } setZIndex(zIndex: number): void { this._ref.zIndex(zIndex); } delete() { this._ref.destroy(); this._ref = null; } getPosition(): { x: number; y: number } { return this._ref.getPosition(); } setPosition(x: number, y: number): void { this._ref.setPosition({ x, y }); } }