Реалізація Signature Pad (електронний підпис) на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація Signature Pad (електронний підпис) на сайті
Проста
від 1 робочого дня до 3 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація Signature Pad (електронний підпис)

Поле для електронного підпису потрібне в контрактах, заявах, актах приймання, медичних формах. Користувач розписується мишею або стилусом, підпис зберігається як SVG або PNG і додається до документа.

Бібліотека signature_pad

signature_pad — мініміалістична бібліотека (8 КБ) від Szimek, яка працює над <canvas>. Підтримує Pointer Events, дотик, стилус з чутливістю до тиску, експорт у PNG/SVG/JPEG.

npm install signature_pad

Базова реалізація

import SignaturePad from 'signature_pad'
import { useEffect, useRef, useCallback } from 'react'

interface SignaturePadProps {
  onSave: (dataUrl: string) => void
  width?: number
  height?: number
}

export function SignatureCanvas({ onSave, width = 500, height = 200 }: SignaturePadProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null)
  const padRef = useRef<SignaturePad | null>(null)

  useEffect(() => {
    const canvas = canvasRef.current!
    padRef.current = new SignaturePad(canvas, {
      minWidth: 0.5,
      maxWidth: 2.5,
      penColor: '#1e293b',
      backgroundColor: 'rgb(255,255,255)',
      throttle: 16, // мс між точками
    })

    // Підтримка HiDPI
    function resizeCanvas() {
      const ratio = Math.max(window.devicePixelRatio || 1, 1)
      canvas.width = canvas.offsetWidth * ratio
      canvas.height = canvas.offsetHeight * ratio
      canvas.getContext('2d')!.scale(ratio, ratio)
      padRef.current!.clear()
    }

    resizeCanvas()
    window.addEventListener('resize', resizeCanvas)
    return () => {
      window.removeEventListener('resize', resizeCanvas)
      padRef.current!.off()
    }
  }, [])

  const handleSave = useCallback(() => {
    if (!padRef.current) return
    if (padRef.current.isEmpty()) {
      alert('Будь ласка, підпишіться')
      return
    }
    // PNG з прозорим фоном
    const dataUrl = padRef.current.toDataURL('image/png')
    onSave(dataUrl)
  }, [onSave])

  const handleClear = useCallback(() => {
    padRef.current?.clear()
  }, [])

  const handleUndo = useCallback(() => {
    const data = padRef.current?.toData()
    if (data && data.length > 0) {
      data.pop() // Видалити останній штрих
      padRef.current?.fromData(data)
    }
  }, [])

  return (
    <div className="border rounded-lg overflow-hidden">
      <canvas
        ref={canvasRef}
        style={{ width, height, touchAction: 'none' }}
        className="block w-full"
      />
      <div className="flex justify-between p-2 bg-gray-50 border-t">
        <div className="flex gap-2">
          <button
            type="button"
            onClick={handleUndo}
            className="text-sm text-gray-600 hover:text-gray-900"
          >
            Скасувати штрих
          </button>
          <button
            type="button"
            onClick={handleClear}
            className="text-sm text-red-500 hover:text-red-700"
          >
            Очистити
          </button>
        </div>
        <button
          type="button"
          onClick={handleSave}
          className="px-4 py-1 bg-blue-600 text-white rounded text-sm"
        >
          Застосувати підпис
        </button>
      </div>
    </div>
  )
}

Експорт у SVG

SVG краще за PNG для підписів — масштабується без втрати якості, менший розмір файлу, можна вставити прямо в PDF:

const svgData = padRef.current.toSVG()
// <svg xmlns="http://www.w3.org/2000/svg" ...>...</svg>

// Або через Blob для збереження файлу
const blob = new Blob([svgData], { type: 'image/svg+xml' })
const url = URL.createObjectURL(blob)

Вставлення підпису в PDF на бекенді

// Node.js, бібліотека pdf-lib
import { PDFDocument } from 'pdf-lib'

async function embedSignatureInPdf(
  pdfBytes: Uint8Array,
  signatureDataUrl: string,
  page: number = 0
): Promise<Uint8Array> {
  const pdfDoc = await PDFDocument.load(pdfBytes)
  const pages = pdfDoc.getPages()
  const targetPage = pages[page]

  // Декодуємо base64 PNG
  const signatureBase64 = signatureDataUrl.replace(/^data:image\/png;base64,/, '')
  const signatureBytes = Buffer.from(signatureBase64, 'base64')
  const signatureImage = await pdfDoc.embedPng(signatureBytes)

  const { width, height } = signatureImage.scale(0.5)

  targetPage.drawImage(signatureImage, {
    x: 60,
    y: 60,
    width,
    height,
    opacity: 1,
  })

  return pdfDoc.save()
}

Інтеграція з React Hook Form

import { Controller } from 'react-hook-form'

function ContractForm() {
  const { control, handleSubmit } = useForm<{
    name: string
    signature: string
  }>()

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <Controller
        control={control}
        name="signature"
        rules={{ required: 'Підпис обов\'язковий' }}
        render={({ field, fieldState }) => (
          <div>
            <SignatureCanvas
              onSave={(dataUrl) => field.onChange(dataUrl)}
              width={500}
              height={180}
            />
            {fieldState.error && (
              <p className="text-red-500 text-sm mt-1">{fieldState.error.message}</p>
            )}
          </div>
        )}
      />
      <button type="submit">Підписати контракт</button>
    </form>
  )
}

Що ми робимо

Підключаємо signature_pad, налаштовуємо HiDPI, експортуємо у PNG або SVG, вставляємо підпис у PDF через pdf-lib на бекенді. Інтегруємо з формою, додаємо валідацію (перевірка, що підпис не порожній).

Тривалість: 0.5–1 день.