UNPKG

qrcode-vue3

Version:

Add a style and an image to your QR code Vue3

339 lines (280 loc) 9.63 kB
/* eslint-disable @typescript-eslint/unbound-method */ import dotTypes from "../constants/dotTypes"; import type { DotType } from "../types"; type GetNeighbor = (x: number, y: number) => boolean; type DrawArgs = { x: number; y: number; size: number; context: CanvasRenderingContext2D; getNeighbor: GetNeighbor; }; type BasicFigureDrawArgs = { x: number; y: number; size: number; context: CanvasRenderingContext2D; rotation: number; }; type RotateFigureArgs = { x: number; y: number; size: number; context: CanvasRenderingContext2D; rotation: number; draw: () => void; }; export default class QRDot { _context: CanvasRenderingContext2D; _type: DotType; constructor({ context, type }: { context: CanvasRenderingContext2D; type: DotType }) { this._context = context; this._type = type; } draw(x: number, y: number, size: number, getNeighbor: GetNeighbor): void { const context = this._context; const type = this._type; let drawFunction; switch (type) { case dotTypes.dots: drawFunction = this._drawDot; break; case dotTypes.classy: drawFunction = this._drawClassy; break; case dotTypes.classyRounded: drawFunction = this._drawClassyRounded; break; case dotTypes.rounded: drawFunction = this._drawRounded; break; case dotTypes.extraRounded: drawFunction = this._drawExtraRounded; break; case dotTypes.square: default: drawFunction = this._drawSquare; } drawFunction.call(this, { x, y, size, context, getNeighbor }); } _rotateFigure({ x, y, size, context, rotation, draw }: RotateFigureArgs): void { const cx = x + size / 2; const cy = y + size / 2; context.translate(cx, cy); rotation && context.rotate(rotation); draw(); context.closePath(); rotation && context.rotate(-rotation); context.translate(-cx, -cy); } _basicDot(args: BasicFigureDrawArgs): void { const { size, context } = args; this._rotateFigure({ ...args, draw: () => { context.moveTo(0, 0) context.arc(0, 0, size / 2, 0, Math.PI * 2); } }); } _basicSquare(args: BasicFigureDrawArgs): void { const { size, context } = args; this._rotateFigure({ ...args, draw: () => { context.moveTo(0, 0) context.rect(-size / 2, -size / 2, size, size); } }); } // if rotation === 0 - right side is rounded _basicSideRounded(args: BasicFigureDrawArgs): void { const { size, context } = args; this._rotateFigure({ ...args, draw: () => { context.moveTo(0, 0) context.arc(0, 0, size / 2, -Math.PI / 2, Math.PI / 2); context.lineTo(-size / 2, size / 2); context.lineTo(-size / 2, -size / 2); context.lineTo(0, -size / 2); } }); } // if rotation === 0 - top right corner is rounded _basicCornerRounded(args: BasicFigureDrawArgs): void { const { size, context } = args; this._rotateFigure({ ...args, draw: () => { context.moveTo(0, 0) context.arc(0, 0, size / 2, -Math.PI / 2, 0); context.lineTo(size / 2, size / 2); context.lineTo(-size / 2, size / 2); context.lineTo(-size / 2, -size / 2); context.lineTo(0, -size / 2); } }); } // if rotation === 0 - top right corner is rounded _basicCornerExtraRounded(args: BasicFigureDrawArgs): void { const { size, context } = args; this._rotateFigure({ ...args, draw: () => { context.moveTo(0, 0) context.arc(-size / 2, size / 2, size, -Math.PI / 2, 0); context.lineTo(-size / 2, size / 2); context.lineTo(-size / 2, -size / 2); } }); } _basicCornersRounded(args: BasicFigureDrawArgs): void { const { size, context } = args; this._rotateFigure({ ...args, draw: () => { context.moveTo(0, 0) context.arc(0, 0, size / 2, -Math.PI / 2, 0); context.lineTo(size / 2, size / 2); context.lineTo(0, size / 2); context.arc(0, 0, size / 2, Math.PI / 2, Math.PI); context.lineTo(-size / 2, -size / 2); context.lineTo(0, -size / 2); } }); } _basicCornersExtraRounded(args: BasicFigureDrawArgs): void { const { size, context } = args; this._rotateFigure({ ...args, draw: () => { context.moveTo(0, 0) context.arc(-size / 2, size / 2, size, -Math.PI / 2, 0); context.arc(size / 2, -size / 2, size, Math.PI / 2, Math.PI); } }); } _drawDot({ x, y, size, context }: DrawArgs): void { this._basicDot({ x, y, size, context, rotation: 0 }); } _drawSquare({ x, y, size, context }: DrawArgs): void { this._basicSquare({ x, y, size, context, rotation: 0 }); } _drawRounded({ x, y, size, context, getNeighbor }: DrawArgs): void { const leftNeighbor = +getNeighbor(-1, 0); const rightNeighbor = +getNeighbor(1, 0); const topNeighbor = +getNeighbor(0, -1); const bottomNeighbor = +getNeighbor(0, 1); const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor; if (neighborsCount === 0) { this._basicDot({ x, y, size, context, rotation: 0 }); return; } if (neighborsCount > 2 || (leftNeighbor && rightNeighbor) || (topNeighbor && bottomNeighbor)) { this._basicSquare({ x, y, size, context, rotation: 0 }); return; } if (neighborsCount === 2) { let rotation = 0; if (leftNeighbor && topNeighbor) { rotation = Math.PI / 2; } else if (topNeighbor && rightNeighbor) { rotation = Math.PI; } else if (rightNeighbor && bottomNeighbor) { rotation = -Math.PI / 2; } this._basicCornerRounded({ x, y, size, context, rotation }); return; } if (neighborsCount === 1) { let rotation = 0; if (topNeighbor) { rotation = Math.PI / 2; } else if (rightNeighbor) { rotation = Math.PI; } else if (bottomNeighbor) { rotation = -Math.PI / 2; } this._basicSideRounded({ x, y, size, context, rotation }); } } _drawExtraRounded({ x, y, size, context, getNeighbor }: DrawArgs): void { const leftNeighbor = +getNeighbor(-1, 0); const rightNeighbor = +getNeighbor(1, 0); const topNeighbor = +getNeighbor(0, -1); const bottomNeighbor = +getNeighbor(0, 1); const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor; if (neighborsCount === 0) { this._basicDot({ x, y, size, context, rotation: 0 }); return; } if (neighborsCount > 2 || (leftNeighbor && rightNeighbor) || (topNeighbor && bottomNeighbor)) { this._basicSquare({ x, y, size, context, rotation: 0 }); return; } if (neighborsCount === 2) { let rotation = 0; if (leftNeighbor && topNeighbor) { rotation = Math.PI / 2; } else if (topNeighbor && rightNeighbor) { rotation = Math.PI; } else if (rightNeighbor && bottomNeighbor) { rotation = -Math.PI / 2; } this._basicCornerExtraRounded({ x, y, size, context, rotation }); return; } if (neighborsCount === 1) { let rotation = 0; if (topNeighbor) { rotation = Math.PI / 2; } else if (rightNeighbor) { rotation = Math.PI; } else if (bottomNeighbor) { rotation = -Math.PI / 2; } this._basicSideRounded({ x, y, size, context, rotation }); } } _drawClassy({ x, y, size, context, getNeighbor }: DrawArgs): void { const leftNeighbor = +getNeighbor(-1, 0); const rightNeighbor = +getNeighbor(1, 0); const topNeighbor = +getNeighbor(0, -1); const bottomNeighbor = +getNeighbor(0, 1); const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor; if (neighborsCount === 0) { this._basicCornersRounded({ x, y, size, context, rotation: Math.PI / 2 }); return; } if (!leftNeighbor && !topNeighbor) { this._basicCornerRounded({ x, y, size, context, rotation: -Math.PI / 2 }); return; } if (!rightNeighbor && !bottomNeighbor) { this._basicCornerRounded({ x, y, size, context, rotation: Math.PI / 2 }); return; } this._basicSquare({ x, y, size, context, rotation: 0 }); } _drawClassyRounded({ x, y, size, context, getNeighbor }: DrawArgs): void { const leftNeighbor = +getNeighbor(-1, 0); const rightNeighbor = +getNeighbor(1, 0); const topNeighbor = +getNeighbor(0, -1); const bottomNeighbor = +getNeighbor(0, 1); const neighborsCount = leftNeighbor + rightNeighbor + topNeighbor + bottomNeighbor; if (neighborsCount === 0) { this._basicCornersRounded({ x, y, size, context, rotation: Math.PI / 2 }); return; } if (!leftNeighbor && !topNeighbor) { this._basicCornerExtraRounded({ x, y, size, context, rotation: -Math.PI / 2 }); return; } if (!rightNeighbor && !bottomNeighbor) { this._basicCornerExtraRounded({ x, y, size, context, rotation: Math.PI / 2 }); return; } this._basicSquare({ x, y, size, context, rotation: 0 }); } }