177 lines
4.0 KiB
JavaScript
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,
|
|
}
|
|
}
|