とある案件で、「手書き署名を収集したい」というものがありました。
これに対するソリューションとして、GASのWebアプリケーションにてCanvasで手書きさせることを提案し、ひとまずは納品できました。
もちろん、署名自体はGoogleドライブに保存されるようになっています。
(Googleフォームで署名が簡単に収集できたら一番よかったのですが、現状は対応されていません。そのうちできるようになるかな、、?)
宣伝
例によって、GASスタンドで販売中ですので、よかったら買ってやってください。
手書き署名収集システム | GASスタンド
手書き署名収集システム 特徴 ・収集した署名画像はGoogleドライブに保存されます ・署名保存先となるGoogleドライブのフォルダIDを指定し、デプロイするだけの簡単設定です ・Webアプリケーションなので、不特定多数からのアクセスに対応することができます 使い方 本システムの使い方は下記となります。 1.署名画像...
完成形
このフォームを送信すると、Googleドライブに署名画像が保存されるのと同時に、スプレッドシートにデータが蓄積されます。
技術的な話
ここからは技術的に頑張った話を書いていきます。
React + Webアプリケーション
最近はReactを使ってWebアプリケーションを作ることが多いです。
ノウハウは下記にまとめてありますので、是非ご覧ください。
GASでReact + Redux(+ Material UI)なWebアプリケーションを作ってみた
むしゃくしゃしてやった。後悔はしている。(時間かけすぎた)ということで、タイトルの通りなのですが、GASのWebアプリケーションにReact + Reduxを組み込んだものを作ってみました。その時の知見を書き綴っていこうと思います...
Canvasによる手書き
ここは結構頑張りました。
以下に、GASで使える <Signature>
コンポーネントを置いておきます。
<script type="text/babel">
const Signature = (props) => {
const { makeStyles, Button } = MaterialUI;
const classes = makeStyles({
root: {
padding: '15px 0',
width: '100%'
},
canvas: {
border: '1px solid #000000',
borderRadius: '7px',
touchAction: 'none',
}
})();
// canvasはDOMを直接操作するためuseRef()経由で操作する
const canvas = React.useRef(null);
// ドラッグ中判断フラグ(マウスを離すか、canvas外へ出たらfalse)
const [drawing, setDrawing] = React.useState(false);
const clear = () => {
const ctx = canvas.current.getContext('2d');
if( ctx ) {
ctx.clearRect(0, 0, props.width, 200);
if (props.onUpdateCanvas) props.onUpdateCanvas(null);
}
};
// 描画に必要なcontextを取得し、線の色、幅をセットする
const getContext = () => {
const ctx = canvas.current.getContext('2d');
ctx.lineWidth = props.lineWidth;
ctx.lineCap = props.lineCap;
ctx.strokeStyle = props.lineColor;
return ctx;
}
// 線描画開始処理。beginPath()で新しいパスを開始する(開始しないと色や太さが変更できない)
const drawStart = (e) => {
const { offsetX: x, offsetY: y } = offsetPosition(e);
setDrawing(true);
const ctx = getContext();
ctx.beginPath();
ctx.moveTo(x, y);
}
// 動きに合わせて線を描画する
const drawMove = (e) => {
if (!drawing) return;
const { offsetX: x ,offsetY: y } = offsetPosition(e);
const ctx = getContext();
ctx.lineTo(x, y);
ctx.stroke();
}
// 線描画完了(canvas更新イベントコールバックを行う)
const endDrawing = () => {
setDrawing(false);
if (props.onUpdateCanvas) props.onUpdateCanvas(canvas.current);
}
// offset(canvas左上からの)を返す。Touch,Mouseイベント両対応
const offsetPosition = (e) => {
if (e.nativeEvent instanceof TouchEvent) {
const rect = e.target.getBoundingClientRect();
const offsetX = (e.nativeEvent.touches[0].clientX - rect.left);
const offsetY = (e.nativeEvent.touches[0].clientY - rect.top);
return { offsetX, offsetY };
} else if (e.nativeEvent instanceof MouseEvent) {
return { offsetX: e.nativeEvent.offsetX ,offsetY: e.nativeEvent.offsetY };
}
}
return (
<div className={classes.root}>
<canvas
ref={canvas}
width={props.width}
height={200}
className={classes.canvas}
onMouseDown={drawStart}
onMouseMove={drawMove}
onMouseUp={endDrawing}
onMouseLeave={endDrawing}
onTouchStart={drawStart}
onTouchMove={drawMove}
onTouchEnd={endDrawing} />
<Button onClick={clear} variant="contained">署名をクリア</Button>
</div>
);
}
Signature.defaultProps = {
width: 500,
lineWidth: 3,
lineColor: "black",
lineCap: "round",
};
</script>
このコンポーネントを使うときは、こんな感じです。
( props.width
と onUpdateCanvas
は定義済みとします)
<Signature width={props.width} onUpdateCanvas={onUpdateCanvas} />
終わりに
GAS+ReactでCanvasを扱うのは少し大変でした。
しつこいですが、よければGASスタンドを覗いていってください(宣伝)
手書き署名収集システム | GASスタンド
手書き署名収集システム 特徴 ・収集した署名画像はGoogleドライブに保存されます ・署名保存先となるGoogleドライブのフォルダIDを指定し、デプロイするだけの簡単設定です ・Webアプリケーションなので、不特定多数からのアクセスに対応することができます 使い方 本システムの使い方は下記となります。 1.署名画像...