Skip to content

Commit

Permalink
Merge pull request #18 from savannabits/2.x
Browse files Browse the repository at this point in the history
Enhancements on the Signature Pad:
  • Loading branch information
coolsam726 authored Aug 12, 2023
2 parents 45c56d2 + 08825b2 commit 9682250
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 76 deletions.
2 changes: 1 addition & 1 deletion resources/dist/components/signature-pad.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion resources/dist/signature-pad.css

Large diffs are not rendered by default.

63 changes: 34 additions & 29 deletions resources/js/components/signature-pad.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import SignaturePad from "signature_pad";

export default function signaturePad(args) {
export default function signaturePad(state, args) {
return {
state: args.state,
state,
ratio: 1,
disabled: args.disabled,
dotSize: args.dotSize,
minWidth: args.minWidth,
Expand All @@ -11,72 +12,76 @@ export default function signaturePad(args) {
penColor: args.penColor,
signaturePad: null,
backgroundColor: args.backgroundColor,
canvas: null,
init() {
const canva = this.$refs.canvas;
if (!canva) {
this.canvas = document.getElementById(args.id);
if (!this.canvas) {
console.error('Canvas is not present')
return;
}

this.signaturePad = new SignaturePad(this.$refs.canvas, {
dotSize: this.dotSize || 2,
minWidth: this.minWidth || 1,
maxWidth: this.maxWidth || 2.5,
minDistance: this.minDistance || 2,
penColor: this.penColor || 'rgb(0,0,0)',
this.signaturePad = new SignaturePad(this.canvas, {
dotSize: this.dotSize || 2,
minWidth: this.minWidth || 1,
maxWidth: this.maxWidth || 2.5,
minDistance: this.minDistance || 2,
penColor: this.penColor || 'rgb(0,0,0)',
backgroundColor: this.backgroundColor || 'rgba(255,255,255,0)'
});
/*if (this.state && this.state.includes('data:image')) {
// console.log('Forming signature from existing image:')
this.signaturePad.fromDataURL(this.state);
}*/

window.addEventListener('resize', e => this.resizeCanvas())
this.resizeCanvas();
if (this.state) {
console.log('state present')
// pass ratio when loading a saved signature
this.signaturePad.fromDataURL(this.state, {ratio: this.ratio});
}

this.signaturePad.addEventListener("beginStroke", () => {
console.log("Signature started");
// console.log("Signature started");
}, {once: false});
this.signaturePad.addEventListener("endStroke", (e) => {
console.log("End stroke")
// console.log("End stroke")
this.save();
this.resizeCanvas()
}, {once: false});

this.signaturePad.addEventListener("afterUpdateStroke", () => {
// console.log("Signature updated");
}, {once: false});
},
async toBlob(url) {
if (url) {
const blob = await (await fetch(url)).blob();
}
},
save() {
this.state = this.signaturePad.toDataURL('image/svg+xml');
// this.state = this.signaturePad.toDataURL('image/png');
// this.state = this.signaturePad.toSVG();
// this.$dispatch('signature-saved', this.signaturePadId);
// console.log(this.state);
this.resizeCanvas()
},
clear() {
this.signaturePad.clear();
this.state = null;
this.resizeCanvas();
},
// The resize canvas function https://github.com/szimek/signature_pad#tips-and-tricks
resizeCanvas() {
const canva = this.$refs.canvas;
const canva = this.canvas;
this.ratio = Math.max(window.devicePixelRatio || 1, 1);
let dimensions = this.getCanvasOffsetDimensions();
console.log(dimensions.width);
console.log(dimensions.height);
// console.log(dimensions.width);
// console.log(dimensions.height);
canva.width = dimensions.width * this.ratio;
canva.height = dimensions.height * this.ratio;
canva.getContext('2d').scale(this.ratio, this.ratio);
// this.signaturePad?.fromData(this.signaturePad.toData());
this.signaturePad?.clear();

this.signaturePad.clear();
if (this.state) {
this.signaturePad.fromDataURL(this.state)
} else {
this.signaturePad?.fromData(this.signaturePad.toData());
}
},
getCanvasOffsetDimensions()
{
const canva = this.$refs.canvas;
const canva = this.canvas;
const element = canva.cloneNode(true);
if (canva.offsetHeight > 0 && canva.offsetWidth > 0) {
return {
Expand Down
108 changes: 70 additions & 38 deletions resources/views/forms/components/fields/signature-pad.blade.php
Original file line number Diff line number Diff line change
@@ -1,49 +1,81 @@
@php
$extraAlpineAttributes = $getExtraAlpineAttributes();
$id = $getId();
$isConcealed = $isConcealed();
$isDisabled = $isDisabled();
$isPrefixInline = $isPrefixInline();
$isSuffixInline = $isSuffixInline();
$prefixActions = $getPrefixActions();
$prefixIcon = $getPrefixIcon();
$prefixLabel = $getPrefixLabel();
$suffixActions = $getSuffixActions();
$suffixIcon = $getSuffixIcon();
$suffixLabel = $getSuffixLabel();
$statePath = $getStatePath();
@endphp
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
>
<div
wire:ignore
ax-load
x-load-css="[
@js(\Filament\Support\Facades\FilamentAsset::getStyleHref('signature-pad-styles', 'coolsam/signature-pad')),
@js(\Filament\Support\Facades\FilamentAsset::getStyleHref('signature-pad-styles', \Coolsam\SignaturePad\Forms\Components\Fields\SignaturePad::PACKAGE_NAME)),
]"
ax-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('signature-pad', 'coolsam/signature-pad') }}"
x-data="signaturePad({
state: $wire.{{ $applyStateBindingModifiers('entangle(\'' . $getStatePath() . '\')') }},
disabled : {{$isDisabled() ? 'true':'false'}},
dotSize : '{{$getStrokeDotSize()}}',
minWidth: '{{$getStrokeMinWidth()}}',
maxWidth : '{{$getStrokeMaxWidth()}}',
minDistance: '{{$getStrokeMinDistance()}}',
penColor: '{{$getPenColor()}}',
backgroundColor: '{{$getBackgroundColor()}}'
})" class="p-2 md:p-4 bg-white dark:bg-gray-700 sm:rounded-md">
<template x-show="state">
<img
class="w-full h-full border-2 dark:border-gray-800 border-dashed rounded-md" :src="state"
alt="sig">
ax-load
ax-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('signature-pad', \Coolsam\SignaturePad\Forms\Components\Fields\SignaturePad::PACKAGE_NAME) }}"
x-data="signaturePad(
$wire.{{ $applyStateBindingModifiers("entangle('{$getStatePath()}')") }},
{
disabled : {{$isDisabled ? 'true':'false'}},
dotSize : '{{$getStrokeDotSize()}}',
minWidth: '{{$getStrokeMinWidth()}}',
maxWidth : '{{$getStrokeMaxWidth()}}',
minDistance: '{{$getStrokeMinDistance()}}',
penColor: '{{$getPenColor()}}',
backgroundColor: '{{$getBackgroundColor()}}',
id: '{{ $id }}',
})"
class="p-2 md:p-4 bg-white dark:bg-gray-500 sm:rounded-md">
<template x-if="state">
<img class="border mx-auto dark:border-gray-700 rounded-lg w-full max-w-[800px]" alt="current_signature" :src="state">
</template>
<canvas
x-ref="canvas"
style="max-height: 200px !important; max-width: 800px !important; border-style: dashed; border-width: initial"
class="w-full h-full m-2 mx-auto border-dotted rounded-md dark:border-gray-800"></canvas>
<div class="flex mt-2 justify-center space-x-2">
<x-filament::button x-if="!signaturePad?.isEmpty()" color="danger" outlined="true" size="sm" @click.prevent="clear()">
{{__('signature-pad::signature-pad.clear')}}
</x-filament::button>
@if(!$isDisabledDownload())
<x-filament::button color="primary" outlined="true" size="sm" icon="heroicon-o-arrow-down-on-square"
@click.prevent="downloadSVG()">.svg
</x-filament::button>
<x-filament::button color="primary" outlined="true" size="sm" icon="heroicon-o-arrow-down-on-square"
@click.prevent="downloadPNG()">.png
</x-filament::button>
<x-filament::button color="primary" outlined="true" size="sm" icon="heroicon-o-arrow-down-on-square"
@click.prevent="downloadJPG()">.jpg
@if(!($isReadOnly() || $isDisabled))
<canvas
before="Hello World"
{{ \Filament\Support\prepare_inherited_attributes($getExtraInputAttributeBag())
->merge($extraAlpineAttributes, escape: false)
->merge([
'disabled' => $isDisabled,
'id' => $id,
'x-ref' => 'canvas',
'x-model' => 'state',
'placeholder' => $getPlaceholder(),
'readonly' => $isReadOnly(),
'required' => $isRequired() && (! $isConcealed),
], escape: false) }}
style="max-height: 100px !important; max-width: 800px !important; border-style: dashed; border-width: initial"
class="w-full h-full m-2 mx-auto border-dashed rounded-md dark:border-gray-700 before:content-[attr(before)]">
</canvas>
<div class="flex mt-2 justify-center space-x-2">
<x-filament::button icon="heroicon-o-arrow-path" color="danger" outlined="true" size="sm" @click.prevent="resizeCanvas()">
</x-filament::button>
@endif
</div>

<template x-if="signaturePad">
<x-filament::button color="danger" outlined="true" size="sm" @click.prevent="clear()">
{{__('signature-pad::signature-pad.clear')}}
</x-filament::button>
</template>
@if(!$isDisabledDownload())
<x-filament::button color="primary" outlined="true" size="sm" icon="heroicon-o-arrow-down-on-square"
@click.prevent="downloadSVG()">.svg
</x-filament::button>
<x-filament::button color="primary" outlined="true" size="sm" icon="heroicon-o-arrow-down-on-square"
@click.prevent="downloadPNG()">.png
</x-filament::button>
<x-filament::button color="primary" outlined="true" size="sm" icon="heroicon-o-arrow-down-on-square"
@click.prevent="downloadJPG()">.jpg
</x-filament::button>
@endif
</div>
@endif
</div>
</x-dynamic-component>
20 changes: 17 additions & 3 deletions src/Forms/Components/Fields/SignaturePad.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,26 @@

namespace Coolsam\SignaturePad\Forms\Components\Fields;

use Coolsam\SignaturePad\Forms\Concerns;
use Coolsam\SignaturePad\Forms\Concerns\HasSignaturePadAttributes;
use Filament\Forms\Components\Concerns;
use Filament\Forms\Components\Contracts;
use Filament\Forms\Components\Field;
use Filament\Support\Concerns\HasExtraAlpineAttributes;

class SignaturePad extends Field
class SignaturePad extends Field implements Contracts\CanBeLengthConstrained, Contracts\HasAffixActions
{
use Concerns\HasSignaturePadAttributes;
use HasSignaturePadAttributes;
use Concerns\CanBeAutocapitalized;
use Concerns\CanBeAutocompleted;
use Concerns\CanBeLengthConstrained;
use Concerns\CanBeReadOnly;
use Concerns\HasAffixes;
use Concerns\HasExtraInputAttributes;
use Concerns\HasInputMode;
use Concerns\HasPlaceholder;
use HasExtraAlpineAttributes;

const PACKAGE_NAME = 'coolsam/signature-pad';

protected string $view = 'coolsam-signature-pad::forms.components.fields.signature-pad';
}
2 changes: 1 addition & 1 deletion src/Forms/Concerns/HasSignaturePadAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ trait HasSignaturePadAttributes

protected string | Closure | null $penColor = 'rgb(0,0,0)';

protected string | Closure | null $backgroundColor = 'rgba(255,255,255, 1)';
protected string | Closure | null $backgroundColor = 'rgba(255,255,255, 0)';

protected bool $hideDownloadButtons = false;

Expand Down
4 changes: 2 additions & 2 deletions src/SignaturePadServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Filament\Support\Facades\FilamentAsset;
use Filament\Support\Facades\FilamentIcon;
use Illuminate\Filesystem\Filesystem;
use Livewire\Testing\TestableLivewire;
use Livewire\Features\SupportTesting\Testable;
use Spatie\LaravelPackageTools\Commands\InstallCommand;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
Expand Down Expand Up @@ -88,7 +88,7 @@ public function packageBooted(): void
}

// Testing
TestableLivewire::mixin(new TestsSignaturePad());
Testable::mixin(new TestsSignaturePad());
}

protected function getAssetPackageName(): ?string
Expand Down
2 changes: 1 addition & 1 deletion tailwind.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module.exports = {
presets: [preset],
content: [
'./src/**/*.php',
'./resources/view/**/*.blade.php',
'./resources/views/**/*.blade.php',
'./vendor/filament/**/*.blade.php',
],
}

0 comments on commit 9682250

Please sign in to comment.