Files
iQR/src/composables/useQrCode.js
T
2026-06-20 14:21:40 +03:00

177 lines
4.0 KiB
JavaScript

import { ref, nextTick } from 'vue'
import QRCode from 'qrcode'
const BASE_QR_SIZE = 256
const MAX_WIDTH_RATIO = 0.8
const MIN_SCALE = 0.5
const SCALE_STEP = 0.1
export function useQrCode() {
const textInput = ref('')
const error = ref('')
const errorColor = ref('red')
const scale = ref(1)
const hasQr = ref(false)
const qrCanvasRef = ref(null)
const qrFrameRef = ref(null)
function logMessage(message, color = 'red') {
error.value = message
errorColor.value = color
}
function getFrameWidth() {
return qrFrameRef.value?.getBoundingClientRect().width ?? 0
}
function getMaxWidth() {
return window.innerWidth * MAX_WIDTH_RATIO
}
function persistScale() {
localStorage.setItem('scale', String(scale.value))
}
async function renderQrCanvas() {
const canvas = qrCanvasRef.value
const userText = textInput.value.trim()
if (!canvas || !userText) return
const width = Math.round(BASE_QR_SIZE * scale.value)
await QRCode.toCanvas(canvas, userText, { width })
}
async function clampScaleIfNeeded() {
await nextTick()
if (getFrameWidth() > getMaxWidth()) {
scale.value = 1
persistScale()
await renderQrCanvas()
}
}
async function generateQR() {
const userText = textInput.value.trim()
if (!userText) {
logMessage('Введите текст для генерации QR-кода!')
return
}
localStorage.setItem('userText', userText)
hasQr.value = true
await nextTick()
try {
await renderQrCanvas()
logMessage('')
await clampScaleIfNeeded()
} catch (err) {
console.error(err)
logMessage('Ошибка при генерации QR-кода.')
hasQr.value = false
}
}
function downloadQR() {
const userText = textInput.value.slice(0, 20)
const canvas = qrCanvasRef.value
if (!canvas) {
logMessage('QR-код не сгенерирован!')
return
}
if (!userText) {
logMessage('Отсутствует текст в поле для ввода')
return
}
const link = document.createElement('a')
link.href = canvas.toDataURL('image/png')
link.download = `qr-code-${userText}.png`
link.click()
logMessage('QR-код скачан!', 'green')
}
function clearQR() {
textInput.value = ''
hasQr.value = false
error.value = ''
scale.value = 1
localStorage.removeItem('userText')
localStorage.removeItem('scale')
}
function closeQrModal() {
hasQr.value = false
}
async function zoomIn() {
if (!qrFrameRef.value || !textInput.value.trim()) {
logMessage('До генерации QR кода маштаб менять нельзя')
return
}
const previousScale = scale.value
scale.value += SCALE_STEP
await renderQrCanvas()
await nextTick()
if (getFrameWidth() > getMaxWidth()) {
scale.value = previousScale
await renderQrCanvas()
logMessage('Достигнут максимальный размер QR кода')
return
}
persistScale()
logMessage('')
}
async function zoomOut() {
if (!qrFrameRef.value || !textInput.value.trim()) {
logMessage('До генерации QR кода маштаб менять нельзя')
return
}
if (scale.value <= MIN_SCALE) {
logMessage('Достигнут минимальный размер QR кода')
return
}
scale.value -= SCALE_STEP
await renderQrCanvas()
persistScale()
logMessage('')
}
async function restoreFromStorage() {
const savedScale = localStorage.getItem('scale')
if (savedScale) {
scale.value = Number(savedScale)
}
const savedText = localStorage.getItem('userText')
if (savedText) {
textInput.value = savedText
await generateQR()
}
}
return {
textInput,
error,
errorColor,
hasQr,
qrCanvasRef,
qrFrameRef,
generateQR,
downloadQR,
clearQR,
closeQrModal,
zoomIn,
zoomOut,
restoreFromStorage,
}
}