Реализация 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, touch, stylus с pressure, экспорт в 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, // ms между точками
    })

    // 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 день.