- 調査・研究
Salesforceで手書きサイン入力を実装する方法
タブレットPCを活用したビジネスでは、署名等の手書きサインの要望を頂くことがあります。
例えば、契約などの手続きにおいて取引先責任者の署名が必要など、Salesforce上でも手書きサインが必要になる場合があります。
本稿では、Visualforceページ上に手書きサインをしてPDF出力する方法として、
VisualforceとjQueryプラグインを活用した実装方法の一例をご紹介します。
jQueryプラグインは「jSignature」を利用します。
このプラグインは、WEBブラウザ上に手書きサインを導入したい時に活用できるプラグインの一つです。
画面イメージ
【初期画面】
グレーのエリアが手書き入力するエリアになります。
【手書き入力】
グレーの枠内でスタイラスペンや指で、電子サインを記入することができます。
【手書きサインの画像化】
「確定」ボタンを押下し、手書きサインを画像化します。
【PDF出力】
「PDF出力」ボタンを押下し、画像化した手書きサインをPDF出力します。
サンプルソース
Visualforce(一部抜粋)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
<body> <div class="container-fluid"> <div id="content"> <apex:pageBlock id="messageBlock"> <div class="alert alert-primary" role="alert">枠内で自由に手書きできます。<br/></div> </apex:pageBlock> // 手書きサインの定義 <div class="card"> <div id="collapseOne" class="collapse show" role="tabpanel" aria-labelledby="headingOne" data-parent="#accordion"> <div class="card-body"> // 手書きサインエリア <apex:pageBlock id="signBlock"> <apex:outputPanel rendered="{!NOT(isSign)}"> // 手書きサインの入力エリア <div id="signature"></div> </apex:outputPanel> <apex:outputPanel rendered="{!isSign}"> // 画像化した手書きサインの出力エリア <apex:image value="data:png;base64,{!inputSignValue}" rendered="{!isSign}"/> </apex:outputPanel> </apex:pageBlock> // 操作ボタン <div id="tools" style="text-align:right;"></div> </div><!-- /.card-body --> </div><!-- /.collapse --> </div><!-- /.card --> // PDF出力の定義 <div id="agreeArea" style="text-align:center;"> <apex:commandButton value="PDF出力" Id="agreeButton" action="{!doPDF}" styleclass="btn btn-info btn-lg"/> </div> <div id="scrollgrabber"></div> <apex:inputHidden value="{!inputSignValue}" id="theHiddenInput"/> <apex:inputHidden value="{!isSign}" id="HiddenInputIsSign"/> <apex:actionFunction name="saveFunc" action="{!uploadAttachment}" reRender="signBlock"/> <apex:actionFunction name="clearFunc" action="{!clearSign}"/> </div> </div> </body> // javascript <script type="text/javascript"> jQuery.noConflict() </script> // 手書きサイン入力エリアの定義 <script> (function($) { var topics = {}; $.publish = function(topic, args) { if (topics[topic]) { var currentTopic = topics[topic], args = args || {}; for (var i = 0, j = currentTopic.length; i < j; i++) { currentTopic[i].call($, args); } } }; $.subscribe = function(topic, callback) { if (!topics[topic]) { topics[topic] = []; } topics[topic].push(callback); return { "topic": topic, "callback": callback }; }; $.unsubscribe = function(handle) { var topic = handle.topic; if (topics[topic]) { var currentTopic = topics[topic]; for (var i = 0, j = currentTopic.length; i < j; i++) { if (currentTopic[i] === handle.callback) { currentTopic.splice(i, 1); } } } }; })(jQuery); </script> <script> (function($){ $(document).ready(function() { // 初期化 var $sigdiv = $("#signature").jSignature({'UndoButton':false}) , $tools = $('#tools') , $extraarea = $('#displayarea') , pubsubprefix = 'jSignature.demo.' // ボタン類の定義 $('<input id="clearBtn" type="button" value="クリア" class="btn btn-info"/>').bind('click', function(e){ clearFunc(); }).appendTo($tools) $('<input id="finishBtn" type="button" value="確定" class="btn btn-info"/>').bind('click', function(e) { var i = new Image() data = $sigdiv.jSignature('getData', 'image') $(document.getElementById('{!$Component.theHiddenInput}')).val(data[1]); $.publish(pubsubprefix + data[0], data); i.src = 'data:' + data[0] + ',' + data[1] if($sigdiv.jSignature('getData','base30')[1].length>1){ $(document.getElementById('{!$Component.HiddenInputIsSign}')).val(true); saveFunc(); } }).appendTo($tools) }) })(jQuery) </script> |
Apex(一部抜粋)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class MockUp_HandwrittenSignatureCtrl { // 手書きサイン入力エリアのクリア public void clearSign() { isSign = false; inputSignValue = ''; } // 手書きサインの画像化および添付へのアップロード public void uploadAttachment() { Attachment att = new Attachment(); att.Id = XXXX; att.ParentId = XXXX; att.Name = 'temp.png'; att.Body = EncodingUtil.base64Decode(inputSignValue); att.ContentType = 'image/png'; upsert att; } // PDF生成およびContactを更新し、生成したPDFもしくは添付したPDFに遷移する public PageReference doPDF(){ if(isSign){ PageReference p = Page.MockUp_HandwrittenSignaturePDF; p.getParameters().put('id', contactRecord.Id); p.setRedirect(true); return p; } return null; } } |
実装手順
jSignatureを静的リソースに登録
GithubからjSignatureをダウンロードし、実装するSalesforce環境の静的リソースに登録します。
登録した資産は3つです。
ダウンロードしたjSignatureのlibs内の「jSignature.min.noconflict.js」「jquery.js」「modernizr.js」です。
手書きサイン入力エリアの定義
入力エリアの定義
<div id=”signature”>が手書きサインの入力エリアになります。
Javascriptで制御されるので、Visualforceではdivタグだけ定義します。
Javascriptは、jSignatureのサンプルが参考になります。
画面読み込み時の初期設定と、線を引くための設定を定義します。
Visualforce
1 2 |
// 手書きサインの入力エリア <div id="signature"></div> |
Javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<script> (function($) { var topics = {}; $.publish = function(topic, args) { if (topics[topic]) { var currentTopic = topics[topic], args = args || {}; for (var i = 0, j = currentTopic.length; i < j; i++) { currentTopic[i].call($, args); } } }; $.subscribe = function(topic, callback) { if (!topics[topic]) { topics[topic] = []; } topics[topic].push(callback); return { "topic": topic, "callback": callback }; }; $.unsubscribe = function(handle) { var topic = handle.topic; if (topics[topic]) { var currentTopic = topics[topic]; for (var i = 0, j = currentTopic.length; i < j; i++) { if (currentTopic[i] === handle.callback) { currentTopic.splice(i, 1); } } } }; })(jQuery); </script> |
ボタンの配置
<div id=”tools” style=”text-align:right;”>は「確定」「クリア」ボタンを配置するためのエリアです。
必要なボタンをバインドさせることで、手書きサインの削除等の操作ができます。
Visualforce
1 2 |
// 操作ボタン <div id="tools" style="text-align:right;"></div> |
Javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<script> (function($){ $(document).ready(function() { // 初期化 var $sigdiv = $("#signature").jSignature({'UndoButton':false}) , $tools = $('#tools') , $extraarea = $('#displayarea') , pubsubprefix = 'jSignature.demo.' // ボタン類の定義 $('<input id="clearBtn" type="button" value="クリア" class="btn btn-info"/>').bind('click', function(e){ clearFunc(); }).appendTo($tools) $('<input id="finishBtn" type="button" value="確定" class="btn btn-info"/>').bind('click', function(e) { var i = new Image() data = $sigdiv.jSignature('getData', 'image') $(document.getElementById('{!$Component.theHiddenInput}')).val(data[1]); $.publish(pubsubprefix + data[0], data); i.src = 'data:' + data[0] + ',' + data[1] if($sigdiv.jSignature('getData','base30')[1].length>1){ $(document.getElementById('{!$Component.HiddenInputIsSign}')).val(true); saveFunc(); } }).appendTo($tools) }) })(jQuery) </script> |
手書きサインの画像化
手書きサインはPDF出力が可能です。
ただし、Visualforce PDFでは URI スキーム形式で符号化された画像はサポートされていません。
手書きサインを画像ファイルとして一度保存しておく必要があります。
今回は、画像化した手書きサインを対象の取引先責任者の添付ファイル(Attachment)として保存します。
添付ファイルに保存した手書きサイン画像をPDF出力時に読み込むことで、手書きサイン画像をPDFに埋め込みます。
実装のポイントは2つです。
- JavascriptからApexクラスを呼ぶので、actionfunction(saveFunc)を定義します。
- 手書きサインの入力チェック
if($sigdiv.jSignature(‘getData’,’base30′)[1].length>1)
何も入力がなかった場合はlengthが0となり、saveFunc()は呼ばれないようにしています。
Visualforce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<apex:inputHidden value="{!inputSignValue}" id="theHiddenInput"/> <apex:inputHidden value="{!isSign}" id="HiddenInputIsSign"/> <apex:actionFunction name="saveFunc" action="{!uploadAttachment}" reRender="signBlock"/> . . . $('<input id="finishBtn" type="button" value="確定" class="btn btn-info"/>').bind('click', function(e) { var i = new Image() data = $sigdiv.jSignature('getData', 'image') $(document.getElementById('{!$Component.theHiddenInput}')).val(data[1]); $.publish(pubsubprefix + data[0], data); i.src = 'data:' + data[0] + ',' + data[1] if($sigdiv.jSignature('getData','base30')[1].length>1){ $(document.getElementById('{!$Component.HiddenInputIsSign}')).val(true); saveFunc(); } }).appendTo($tools) |
APEX
1 2 3 4 5 6 7 8 9 |
// 手書きサインの画像化および添付へのアップロード public void uploadAttachment() { Attachment att = new Attachment(); att.Id = XXXX; att.ParentId = XXXX; att.Name = 'temp.png'; att.Body = EncodingUtil.base64Decode(inputSignValue); upsert att; } |
PDF出力処理の実装
手書きサイン画像は、添付ファイル(Attachment)に保存した画像を読み込みます。
Visualforce
1 2 3 4 |
// タイトル <div><h3>PDF出力結果</h3></div> // 手書きサイン画像 <apex:image url="{!attFileURL}" width="50%" height="50%" /> |
大変だったこと
手書きサインがPDFに表示されない
「PDF」ボタンを押下し、PDFが出力させる処理を作成しましたが、
出力されたPDFに手書きサインの画像データが表示されない事象が発生しました。
表示されない原因は、手書きサインの画像データがURI スキーム形式だったことです。
前述でも記載しましたが、Visualforce PDFは URI スキーム形式で符号化された画像はサポートされていません。
今回の対処方法は、手書きサインを画像化して添付ファイル(Attachment)に保存することで対処しました。